DOM 编程

2022-12-31 0 873

页面只不过是颗树,JS怎样操作方式这棵树?

JS操作方式没法。让应用程序往window上有两个document。

JS用document操作方式页面

“用document第一类操作方式整座页面”此种价值观就叫作文件格式第一类数学模型(Document Object Model)

读懂两个历史事实:DOM极难用

下科白他们会想配套措施化解那个痛点(PCB)。

假如你真的DOM天真,千万别揣测他们,你真的是对的。

DOM的USB结构设计的十分反人类文明,引致后端开发人员不得不采用jQuery去操作方式DOM。而后Vue、ReactEngilbert。他们坎氏Vue或React来替代操作方式DOM。

他们从不会用DOM便携式的机能操作方式DOM,即使毕竟是反人类文明。

但他们却是ThoubalDOM,要不然看不懂 交互式DOM 和 jQuery。

其他

1.斜线表达式不全力支持this,有斜线表达式就无法有this!

2.在html里,无论有啥字符单厢拉出两个字符。

3.JS里头的特性泛称为properties,HTML里头的特性泛称为attributes。

DOM提供更多的大部份表达式(API)

有许多API

1.window.id或是间接id //最慢

2.document.getElementById(id)

3.document.getElementsByTagName(div)[0] //找到大部份标签名为div的第1个元素

4.document.getElementsByClassName(red)[0] //找到大部份class名为red的第1个元素

5.document.querySelector(#id)

6.document.querySelectorAll(#id)[0]

用哪两个

1.工作中用querySelector和querySelectorAll

2.做demo间接用id

3.要兼容IE的才用getElement(s)ByXXX

id=”kw” window.kw 或是 kw document.querySelector(#id) //(css选择器的写法) 例如:document.querySelector(div>span:nth-child(2))

代码:window.onclick=()=>{console.

变态

document.all是IE发明的奇葩,第6个falsy值。

document.all以前用来区分是否是IE(现在document.all默认为假)

if(document.all){console.log(ie应用程序); 只能在ie运行} else{console.log(其他应用程序); 只能在非ie运行} 结果:其他应用程序 不做判断时可以间接用 document.all[2]

都是第一类。

只需要搞清第一类自身有哪些特性,以及它的原型有哪些即可。

div 原型链

元素的 自身特性 和 6层原型链

js的大部份第一类都有个隐藏特性,那个隐藏特性指向了第一类的原型。

div.__proto__===HTMLDivElement.prototype

百度应用程序 let div=document.getElementsByTagName(“div”)[0] console.dir(div) 输出:div#wrapper.wrapper_new … //div自身特性 [[Prototype]]: HTMLDivElement //大部份div的共同特性 [[Prototype]]: HTMLElement //大部份标签的共同特性 [[Prototype]]: Element //大部份元素的属性 [[Prototype]]: Node //节点 [[Prototype]]: EventTarget 1.addEventListener 添加 2.dispatchEvent 触发 3.removeEventListener 删除 [[Prototype]]: Object //根第一类

节点Node?元素Element?怎么区分?

节点分为标签和文字

节点包括下面几种不同的节点:

x.nodeType得到两个数字

1表示元素Element,也叫标签Tag

3表示文本Text

8表示注释Comment

9表示文件格式Document

例子

百度应用程序 div.nodeType 输出:1 div.childNodes 输出:NodeList(6) [略…] div.firstChild 输出:#text div.firstChild.textContent 结果:\n div.firstChild.nodeType 3
DOM 编程

由于div是由HTMLDivElement那个表达式构造出来的,所以那个构造表达式往this(div)上添加了hidden特性、…

也继承了Element,Element给this加了id、…

也是Node构造的,Node给this加了childNodes/firstChild…

每一层构造表达式单厢给this上有特性

节点的增删改查

一.增

创建两个标签节点

let div1=document.createElement(div)

document.createElement(style)

document.createElement(script)

document.createElement(li)

创建两个文本节点

let text1=document.createTextNode(你好)

标签里头插入文本

1 div1.appendChild(text1)

2 推荐

let div1=document.createElement(div)

div1.innerText=你好 或是 div1.textContent=你好

但无法用div1.appendChild(你好)

不同的原型提供更多了不同的表达式,但无法混着用!

插入页面中

这时只会创建到内存不会显示到页面

你创建的标签默认处于JS线程中,必须把它插到head(`<style>或<link>`)或是body里头才会生效。

document.body.appendChild(div1)或是 已在页面中的元素.appendChild(div1)

document.body.appendChild(div1) div1.style.top = 0 div1.style.left = 0 div1.style.color=red div2.style.width=300

appendChild

代码

页面中有 div#test1 和 div#test2

let div=document.createElement(div)

test1.appendChild(div)

test2.appendChild(div)

请问最终div出现在哪里?

test2里头。即使两个元素无法出现在两个地方,除非复制一份。

let div1=document.createElement(div) let text1=document.createTextNode(你好) div1.appendChild(text1) div1 document.head.appendChild(div1) document.body.appendChild(div1) 复制,让head body两个地方都有 let div2=div1.cloneNode(true) //复制 document.head.appendChild(div1) document.body.appendChild(div2)

二.删

1 parentNode.removeChild(childNode)

2 childNode.remove() 注意:不全力支持ie

例子

div1.parentNode //id=”div1″ div1.parentNode.removeChild(div1)

怎样彻底删除节点?

div2.remove()

div2=null

三.改

1.改特性

(1)写标准特性

1 改class:div1.className=red 会覆盖之前的,id=”div1″

2 改class:div1.classList.add(green)

改style:div1.style=width:200px;color:blue; 会覆盖之前的

改style的一部分:div1.style.width=200px

大小写:div1.style.backgroundColor=white //大部份用-隔开的,用大写替代

改data-* 特性:div1.dataset.x=fuck 添加自定义特性

e(data-x)或是div1.dataset.x

自定义特性 s_is.dataset.x=fuck //id=s_is 输出:dataset.x=fuck

(2)读标准特性

查看样式、id、class:div1.style/id/className

1 div2.classList/a.href

2 div2.getAttribute(class)/a.getAttribute(href)

2种方法都行,读样式、id、class时都一样,只是在读链接时值有点不同:

用href时,有可能应用程序会自动加一些东西。

例子

<a id=test href=”/xxx”>/xxx</a> 1 console.log(test.href) //应用程序会自动加些东西 输出:”JS Bin not found” 2 console.log(test.getAttribute(h

(3)改on开头的特性(改事件处理表达式)

div1.onclick默认为null

默认点击div不会有任何事发生

但假如你把div1.onclick改成两个表达式fn,那么点击div时应用程序就会调用那个表达式。

而且是这样调用的fn.call(this,event)event是第1个参数

div1会被当作this,event则包含了点击事件的大部份信息,如坐标

假如需要this,就无法用斜线表达式,用function才能得到this。即使斜线表达式不全力支持this。

div1.addEventListener是升级版的div1.onclick,后面会说

<div id=div1>test</div> console.log(div1.onclick); 输出:null div1.onclick=()=>{ console.log(hello) } div1.onclick=function(x){ //event是第1个参数 x console.log(this) //this就是div1,x就是event console.log(x) } //原理:div1.onclick.call(div1,event)

点击后,this 和 x 是应用程序用call传进来的

(4)改内容 //id=”div1″

改文本内容

div1.innerText=xxx或是 div1.textContent=xxx

改html内容

div1.innerHTML=`<p> <strong>重要</strong> </p>`

字符限制在2万以内超出应用程序会卡死

改标签

div1.innerHTML=

div1.appendChild(div2)

先清空再加内容

(5)改爸爸

newParent.appendChild(div1)

查爸爸

node.parentNode或是node.parentElement

查爷爷

node.parentNode.parentNode

例子

<div id=div1></div> div1.parentNode div1.parentNode.parentNode div1.children

查子代

2 node.children

当子代变化时,两者也会实时变化吗?

单厢实时变化。querySelectorAll不会实时更新

let c=document.querySelectorAll(li)

<ul id=test> <li>1</li> <li>2</li> </ul> console.log(test.childNodes.length) console.log(test.childNodes) 5 //在html里,无论有啥字符单厢拉出两个字符。 <ul id=test><li>1</li><li>2</li></ul> console.log(test.childNodes.length) //2

console.log(test.children.length) //2

查兄弟姐妹

1 node.parentNode.childNodes //需要排除他们以及大部份的文本节点,更麻烦

2 node.parentNode.children //需要排除他们

id=div2 div2.parentNode.childNodes //包含他们 let siblings=[] //遍历,排除他们 let c = div2.parentNode.children for(let i=0;i<c.length;i++){ if(c[i]!=div2){ siblings.push(c[i]) } }

查看老大

node.firstChild

查看老幺

node.lastChild

查看上两个哥哥/姐姐

node.previousSibling

查看下两个弟弟/妹妹

node.nextSibling //包含文本节点

可以避开文本节点node.previousElementSibling

例子

id=div2 document.body.firstChild //或是document.body.children[0] document.body.lastChild div2.previousSibling div2.previousElementSibling

遍历两个div里头的所有元素

travel=(node,fn)=>{ //接收节点和表达式 fn(node) //传参,fn在后面定义 if(node.children){ //假如当前节点有子元素,遍历子元素 for(let i=0;i<node.children.length;i++){ travel(node.children[i],fn)//每两个节点再travel下,递归的travel } } } travel(div1,(node)=>console.log(node))//斜线函数是fn

DOM 操作方式跨线程(高级知识)

应用程序机能划分:应用程序分为渲染引擎和JS引擎

跨线程操作方式

各线程各司其职

js引擎无法操作方式页面,只能操作方式js

渲染引擎无法操作方式js,只能操作方式页面

document.body.appendChild(div1)

这句js是怎样改变页面的?

跨线程通信

当应用程序发现js在body里头加了个”div1″第一类

应用程序就会通知渲染引擎在页面里也新增两个div元素

新增的div1元素大部份特性都照抄div1第一类

时间浪费在应用程序。应用程序发现后去通知线程,那个是要时间的。所以操作方式会比其他操作方式慢。

为什么要分两个线程?

让每一块都变的简单,好优化。

变得慢可以优化其他的点,比如可以单独给渲染做优化。

DOM 编程

插入新标签的完整过程

在div1放入页面之前,你对div1大部份的操作方式都属于js线程内的操作方式。

把div1放入页面之时,应用程序会发现JS的意图,就会通知渲染线程在页面中渲染div1对应的元素。

把div1放入页面之后,你对div1的操作方式都有可能会触发重新渲染

div1.id=newId可能会重新渲染,也可能不会

div1.title=new可能会重新渲染,也可能不会

例子

<div title=”titlehi”></div> div::after{ content:attr(title); } 输出:titlehi

假如连续对div1多次操作方式,浏览器可能会合并成一次操作方式,也可能不会

特性同步

标准特性

对div1的标准特性的修改,会被应用程序同步到页面中

比如id、className、title

data-*特性

会同步

非标准特性

对非标准特性的修改,则只会停留在js线程中,不会同步

假如你有自定义特性想被同步,可以采用data-作为前缀

DOM 编程

property vs attribute

JS特性泛称为properties,HTML特性泛称为attributes。

property特性

js线程中div1的大部份特性,叫作div1的property

attribute也是特性

渲染引擎中div1对应标签的特性,叫作attribute

区别

大部份时候,同名的property和attribute值相等

但假如不是标准特性,那么它俩只会在一开始时相等

但注意attribute只全力支持字符串

property全力支持字符串、布尔等类型

面试题

为什么DOM操作方式比较慢?

时间浪费在应用程序。应用程序发现后去通知线程,那个是要时间的。所以操作方式会比其他操作方式都慢。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务