JavaScript DOM
Posted 京京吖!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript DOM相关的知识,希望对你有一定的参考价值。
html DOM 节点
在 HTML DOM 中,所有事物都是节点。DOM 是被视为节点树的 HTML。
DOM Nodes
DOM 节点
根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:
- 整个文档是一个文档节点
- 每个 HTML 元素是元素节点
- HTML 元素内的文本是文本节点
- 每个 HTML 属性是属性节点
- 注释是注释节点
节点父、子和同胞
节点树中的节点彼此拥有层级关系。
我们常用父(parent)、子(child)和同胞(sibling)等术语来描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。
- 在节点树中,顶端节点被称为根(root)。
- 每个节点都有父节点、除了根(它没有父节点)。
- 一个节点可拥有任意数量的子节点。
- 同胞是拥有相同父节点的节点。
下面的图片展示了节点树的一部分,以及节点之间的关系:
请看下面的 HTML 片段:
从上面的 HTML 中:
- <html> 节点没有父节点;它是根节点
- <head> 和 <body> 的父节点是 <html> 节点
- 文本节点 "Hello world!" 的父节点是 <p> 节点
并且:
- <html> 节点拥有两个子节点:<head> 和 <body>
- <head> 节点拥有两个子节点:<meta> 与 <title> 节点
- <title> 节点也拥有一个子节点:文本节点 "DOM 教程"
- <h1> 和 <p> 节点是同胞节点,同时也是 <body> 的子节点
并且:
- <head> 元素是 <html> 元素的首个子节点
- <body> 元素是 <html> 元素的最后一个子节点
- <h1> 元素是 <body> 元素的首个子节点
- <p> 元素是 <body> 元素的最后一个子节点
警告!
DOM 处理中的常见错误是希望元素节点包含文本。
在本例中:<title>DOM 教程</title>,元素节点 <title>,包含值为 "DOM 教程" 的文本节点。
可通过节点的 innerHTML 属性来访问文本节点的值。
HTML DOM 方法
HTML DOM 方法是我们可以在节点(HTML 元素)上执行的动作。
HTML DOM 属性是我们可以在节点(HTML 元素)设置和修改的值。
编程接口
可通过 javascript (以及其他编程语言)对 HTML DOM 进行访问。
所有 HTML 元素被定义为对象,而编程接口则是对象方法和对象属性。
方法是您能够执行的动作(比如添加或修改元素)。
属性是您能够获取或设置的值(比如节点的名称或内容)。
getElementById() 方法
getElementById() 方法返回带有指定 ID 的元素:
实例:
HTML DOM 对象 - 方法和属性
一些常用的 HTML DOM 方法:
- getElementById(id) - 获取带有指定 id 的节点(元素)
- appendChild(node) - 插入新的子节点(元素)
- removeChild(node) - 删除子节点(元素)
一些常用的 HTML DOM 属性:
- innerHTML - 节点(元素)的文本值
- parentNode - 节点(元素)的父节点
- childNodes - 节点(元素)的子节点
- attributes - 节点(元素)的属性节点
一些 DOM 对象方法
这里提供一些您将在本教程中学到的常用方法:
方法 | 描述 |
---|---|
getElementById() | 返回带有指定 ID 的元素。 |
getElementsByTagName() | 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。 |
getElementsByClassName() | 返回包含带有指定类名的所有元素的节点列表。 |
appendChild() | 把新的子节点添加到指定节点。 |
removeChild() | 删除子节点。 |
replaceChild() | 替换子节点。 |
insertBefore() | 在指定的子节点前面插入新的子节点。 |
createAttribute() | 创建属性节点。 |
createElement() | 创建元素节点。 |
createTextNode() | 创建文本节点。 |
getAttribute() | 返回指定的属性值。 |
setAttribute() | 把指定属性设置或修改为指定的值。 |
HTML DOM 属性
属性是节点(HTML 元素)的值,您能够获取或设置。
编程接口
可通过 JavaScript (以及其他编程语言)对 HTML DOM 进行访问。
所有 HTML 元素被定义为对象,而编程接口则是对象方法和对象属性。
方法是您能够执行的动作(比如添加或修改元素)。
属性是您能够获取或设置的值(比如节点的名称或内容)。
innerHTML 属性
获取元素内容的最简单方法是使用 innerHTML 属性。
innerHTML 属性对于获取或替换 HTML 元素的内容很有用。
实例 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <p id="intro">Hello World!</p> <script> var txt=document.getElementById("intro").innerHTML; document.write(txt); </script> </body> </html>
在上面的例子中,getElementById 是一个方法,而 innerHTML 是属性。
innerHTML 属性可用于获取或改变任意 HTML 元素,包括 <html> 和 <body>。 |
nodeName 属性规定节点的名称。
- nodeName 是只读的
- 元素节点的 nodeName 与标签名相同
- 属性节点的 nodeName 与属性名相同
- 文本节点的 nodeName 始终是 #text
- 文档节点的 nodeName 始终是 #document
注意: nodeName 始终包含 HTML 元素的大写字母标签名。
nodeValue 属性
nodeValue 属性规定节点的值。
- 元素节点的 nodeValue 是 undefined 或 null
- 文本节点的 nodeValue 是文本本身
- 属性节点的 nodeValue 是属性值
下面的例子会取回 <p id="intro"> 标签的文本节点值:
实例 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <p id="intro">Hello World!</p> <script> x=document.getElementById("intro"); document.write(x.firstChild.nodeValue); </script> </body> </html>
nodeType 属性
nodeType 属性返回节点的类型。nodeType 是只读的。
比较重要的节点类型有:
元素类型 | NodeType |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
实例:
HTML DOM 访问
访问 HTML DOM - 查找 HTML 元素。
访问 HTML 元素(节点)
访问 HTML 元素等同于访问节点
您能够以不同的方式来访问 HTML 元素:
- 通过使用 getElementById() 方法
- 通过使用 getElementsByTagName() 方法
- 通过使用 getElementsByClassName() 方法
HTML DOM - 修改 HTML 内容
通过 HTML DOM,JavaScript 能够访问 HTML 文档中的每个元素。
改变 HTML 内容
改变元素内容的最简单的方法是使用 innerHTML 属性。
下面的例子更改 <p> 元素的 HTML 内容:
实例:
改变 HTML 样式
实例:
// 样式 style使用事件
HTML DOM 允许您在事件发生时执行代码。
当 HTML 元素"有事情发生"时,浏览器就会生成事件:
HTML DOM - 元素
添加、删除和替换 HTML 元素。
添加:
替换:
HTML DOM - 事件
对事件作出反应
当事件发生时,可以执行 JavaScript,比如当用户点击一个 HTML 元素时。
如需在用户点击某个元素时执行代码,请把 JavaScript 代码添加到 HTML 事件属性中:
HTML 事件的例子:
- 当用户点击鼠标时
- 当网页已加载时
- 当图片已加载时
- 当鼠标移动到元素上时
- 当输入字段被改变时
- 当 HTML 表单被提交时
- 当用户触发按键时
onclick事件
onchange 事件
onchange 事件常用于输入字段的验证。
onload 和 onunload 事件
当用户进入或离开页面时,会触发 onload 和 onunload 事件。
onload 事件可用于检查访客的浏览器类型和版本,以便基于这些信息来加载不同版本的网页。
onload 和 onunload 事件可用于处理 cookies。
onmouseover 和 onmouseout 事件
onmouseover 和 onmouseout 事件可用于在鼠标指针移动到或离开元素时触发函数。
鼠标动画1:
div.onmousemove=function(e){
// 获取鼠标位置
// console.log(e.x,e.y);
span.style.top=e.y+"px";
span.style.left=e.x+"px";
}
例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 200px; height: 200px; background-color: red; } span{ position: absolute; top: 10px; left: 10px; } </style> <script> // e 事件对象 window.onload=function(){ var div=document.querySelector("div"); var span=document.querySelector("span"); div.onmousemove=function(e){ // 获取鼠标位置 // console.log(e.x,e.y); span.style.top=e.y+"px"; span.style.left=e.x+"px"; } } </script> </head> <body> <div></div> <span>这是一段文字</span> </body> </html>
鼠标动画2:
例子:点击小图片显示出大图片
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ padding:0; margin:0; } body{ position: relative; } ul{ width: 1000px; min-width:600px; margin: 0 auto; display:flex; justify-content:space-between; align-items:center; list-style: none; } .big{ width: 300px; height: 300px; position: absolute; display: none; } </style> <script> window.onload=function(){ var imgs=document.querySelectorAll("li img"); var big=document.querySelector(".big"); for (let i = 0; i < imgs.length; i++) { imgs[i].onmousemove=function(e){ big.style.top=e.y+10+"px"; big.style.left=e.x+10+"px"; big.src=this.src; } imgs[i].onmouseout=function(){ big.style.display="none"; } imgs[i].onmouseenter=function(){ big.style.display="block"; } } } </script> </head> <body> <ul> <li><img src="./a/toplist_a01.jpg" alt=""></li> <li><img src="./a/toplist_a02.jpg" alt=""></li> <li><img src="./a/toplist_a03.jpg" alt=""></li> <li><img src="./a/toplist_a04.jpg" alt=""></li> <li><img src="./a/toplist_a05.jpg" alt=""></li> <li><img src="./a/toplist_a06.jpg" alt=""></li> </ul> <img class="big" src="./a/toplist_a01.jpg" alt=""> </body> </html>
tab切换 (选项卡)
2个for循环
法一:
for (let i = 0; i < as.length; i++) { as[i].onclick=function(){ for (var j = 0; j < as.length; j++) { as[j].className=""; } this.className="active"; } }
法二:
// ajax
var url=this.attributes["data-url"].value;
例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ padding: 0; margin: 0; } a{ text-decoration:none; color: #333;2)性能测试
下图是对两段代码的性能测试,可在此处查看在线性能测试。
1. 第一段每一次循环都直接用DOM赋值
2. 第二段是先将内容缓存到局部变量中,最后使用一次DOM赋值。
测试结果以每秒钟执行测试代码的次数(Ops/sec)显示,这个数值越大越好。
除了这个结果外,同时会显示测试过程中的统计误差,以及相对最好的慢了多少(%),统计误差也是非常重要的指标。
二、选择器API
有时候为了得到需要的元素列表,需要组合调用getElementById等并遍历返回的节点,但这种繁密的过程效率低下。
使用CSS选择器是一种定位节点的便利途径,querySelectorAll就是DOM的原生方法。
//DOM组合APIvar elements = document.getElementById(‘menu‘).getElementsByTagName(‘a‘);//替换为简便的CSS选择器var elements = document.querySelectorAll(‘#menu a‘);上面的例子不能体现效率的区别, 后面又改写了一个。在codepen中书写了一个例子,可以在线查看。
//从列表中选出CSS类是one的节点var elements = document.querySelectorAll(‘#menu a.one‘);var elements = document.getElementById(‘menu‘).getElementsByTagName(‘a‘), list=[];for(var i=0, len=elements.length; i<len; i++) { if(elements[i].className == ‘one‘) { list.push(elements[i]); } }
三、重绘与重排
在《CSS动画与JavaScript动画》中层提到过页面渲染的一般过程为JavaScript > 计算样式 > 布局 > 绘制 > 渲染层合并。
Layout(重排)和Paint(重绘)是整个环节中最为耗时的两环,所以我们尽量避免着这两个环节。
当DOM的变化影响了元素的几何属性(宽和高)将会发生重排(reflow);
完成重排后,浏览器会重新绘制受影响的部分到屏幕中,此过程为重绘(repaint)。
1)重排何时发生
1. 添加或删除可见的DOM元素
2. 元素位置改变
3. 元素尺寸改变(包括外边距、内边距、边框宽度、宽、高等属性)
4. 内容改变,例如文本改变或图片被不同尺寸的替换掉。
5. 页面渲染器初始化。
6. 浏览器窗口尺寸改变。
2)批量执行重排
下面代码看上去会重排3次,但其实只会重排1次,大多数浏览器通过队列化修改和批量显示优化重排版过程。
//渲染树变化的排队和刷新var ele = document.getElementById(‘myDiv‘); ele.style.borderLeft = ‘1px‘; ele.style.borderRight = ‘2px‘; ele.style.padding = ‘5px‘;但下列操作将会强迫队列刷新并要求所有计划改变的部分立刻应用:
offsetTop, offsetLeft, offsetWidth, offsetHeight scrollTop, scrollLeft, scrollWidth, scrollHeight clientTop, clientLeft, clientWidth, clientHeight getComputedStyle() (currentStyle in IE)(在 IE 中此函数称为 currentStyle)像offsetHeight属性需要返回最新的布局信息,因此浏览器不得不执行渲染队列中的“待处理变化”并触发重排以返回正确的值。
对于尺寸坐标相关的信息可以参考《JavaScript中尺寸、坐标》。
3)最小化重绘和重排
1. cssText和class
cssText可以一次设置多个CSS属性。class也可以一次性设置,并且更清晰,更易于维护,但有前提条件,就是不依赖于运行逻辑和计算的情况。
// cssTextele.style.cssText = ‘border-left: 1px; border-right: 2px; padding: 5px;‘;// classele.className = ‘active‘;在《JavaScript特性(attribute)、属性(property)和样式(style)》详细介绍了CSS相关的JS操作。
2. 批量修改DOM
2.1 隐藏元素display:none,应用修改,重新显示display:block。
2.2 使用文档片段fragment,在片段上操作节点,再拷贝回文档。
//文档片段(fragment)var fragment = document.createDocumentFragment();var li = document.createElement(‘li‘); li.innerHTML = ‘banana‘; fragment.appendChild(li); document.getElementById(‘fruit‘).appendChild(fragment);2.3 将原始元素拷贝到一个脱离文档的节点中(例如position:absolute),修改副本,完成后再替换原始元素。
四、其它章节性能介绍
1)第一章 加载和执行
将<script>标签放到页面底部,也就是</body>闭合标签之前。
多种无阻塞下载JavaScript的方法:
1. 使用<script>标签的defer属性。页面解析到<script>标签时开始下载,但并不会执行,直到DOM加载完(onload事件触发前)。
2. 动态创建<script>元素来下载并执行代码。无论在何时启动下载,文件的下载和执行过程不会阻塞页面其它进程,但返回的代码通常会立刻执行。
3. 使用XHR对象下载JavaScript代码并注入页面中。优点是下载后不会自动执行,所有主流浏览器都支持,但不能跨域下载。
2)第二章 数据存取
1. 每遇到一个变量,就会经历一次标识符解析的过程,以决定在哪里获取和存储数据。在执行环境的作用域中,标识符所在的位置越深,读写速度也就越慢。因此函数中读写局部变量是最快的,读写全局变量是最慢的。
2. 由于对象成员可能包含其它成员,例如window.location.href。每次遇到点操作符,嵌套成员会导致JavaScript引擎搜索全部对象成员。对象成员嵌套越深,读取速度越慢。location.href就比window.location.href快。
3)第五章 字符串与正则表达式
str = str + "one";//性能高str = "one" + str;//性能差1. 除IE外,浏览器会简单的将第二个字符串拷贝到第一个的后面,如果变量str很大的话,就会出现性能损耗(内存占用)就会很高。
2. 正则优化包括:减少分支数量,缩小分支范围;使用非捕获数组;只捕获感兴趣的文本以减少后期处理;使用合适的量词;化繁为简,分解复杂的正则;
4)第六章 快速响应的用户界面
使用定时器让出时间片段,分割大型任务,在文章《JavaScript定时器分析》中有具体分析。
5)第七章 Ajax
Mutipart XHR允许客户端只用一个HTTP请求就可以从服务器向客户端传送多个资源。
将资源文件(CSS、HTML、JavaScript、Base64编码图片)打包成一个由双方约定的字符串分隔符,发送到客户端。
然后用JavaScript代码处理这个字符串,根据“mime-type”类型和传入的头信息解析每个资源。
6)第九章 构建并部署高性能JavaScript应用
1. 合并JavaScript文件以减少HTTP请求数。
2. 压缩JavaScript文件。
3. 在服务器端压缩JavaScript文件(Gzip编码)。
4. 正确设置HTTP响应头来缓存JavaScript文件,通过向文件名增加时间戳避免缓存问题。
5. 使用CDN(Content Delivery Network)提供JavaScript文件。
第八章 编程实践内容比较多,单独令出来作为一节。
五、第八章 编程实践
1)使用Object/Array直接量
代码例下:
var myObject = { name: "pwstrick", age: 29 };var myArr = ["pwstrick", 29];2)避免重复工作
也就是惰性模式。减少每次代码执行时的重复性分支判断,通过对对象重定义来屏蔽原对象中的分支判断。
惰性模式分为两种:第一种文件加载后立即执行对象方法来重定义,第二种是当第一次使用方法对象时来重定义。可参考在线demo代码。
在文章《JavaScript设计模式》中有更多的设计模式介绍。
3)位运算
1. 用位运算取代纯数学操作,比如对2取模digit%2可以判断偶数与奇数。
2. 位掩码技术,使用单个数字的每一位来判断选项是否成立。掩码中每个选项的值都是2的幂。例如:
var OPTION_A = 1, OPTION_B = 2, OPTION_C = 4, OPTION_D = 8, OPTION_E = 16;//用按位或运算创建一个数字来包含多个设置选项var options = OPTION_A | OPTION_C | OPTION_D;//接下来可以用按位与操作来判断给定的选项是否可用//选项A是否在列表中if(options & OPTION_A) { //...}3. 用按位左移(<<)做乘法,用按位右移做除法(>>),例如digit*2可以替换成digit<<2。
4)原生方法
无论你的代码如何优化,都比不上JavaScript引擎提供的原生方法快。
1. 数学运算用内置的Math对象中提供的方法。
2. 用原生的CSS选择器查找DOM节点,querySelector或querySelectorAll。
以上是关于JavaScript DOM的主要内容,如果未能解决你的问题,请参考以下文章
更改页面javascript代码(TamperMonkey)以将键盘笔触发送到父DOM
jquery 对象的 heightinnerHeightouterHeight 的区别以及DOM 元素的 clientHeightoffsetHeightscrollHeightoffset(代码片段