JavaScript DOM操作详解

什么是DOM?

文档对象模型(Document Object Model),是 W3C 组织推荐的处理可拓展标记语言(HTML或者XML)的编程接口。

W3C 已经定义了一系列的 DOM 接口,通过这些接口可以改变网页的内容、结构和样式。

DOM 树

image-20220615154553565

  • 文档:一个页面就是一个文档,DOM 中使用 document 表示
  • 元素:页面中的所有标签都是元素,DOM中使用 element 表示
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示

DOM 把以上内容都看成是对象

获取元素

代码归属描述
document.getElementById(‘nav’)DOM 老方法不推荐通过元素的 id 属性值获取元素,只返回第一个元素
document.getElementByTagName(‘div’)DOM 老方法不推荐通过元素的标签名获取元素,将选择到的所有对象存入伪数组并返回
document.querySelector(‘.nav li’)H5 新增方法推荐通过选择器的方法获取元素,只返回第一个对象
document.querySelectorAll(‘.nav li’)H5 新增方法推荐通过选择器的方法获取元素,将选择到的所有对象存入伪数组并返回
document.getElementByClassName(‘nav’)H5 新增方法通过元素的类名获取元素,将选择到的所有对象存入伪数组并返回,不兼容ie
document.body获取整个文档的body部分
document.documentElement获取整个文档,即html部分

根据元素 ID 获取 getElementById()

  • 此方法为 DOM 老 API,兼容性好,但是不推荐开发时使用。

  • 此方法只返回获取到的第一个元素对象。

  • 语法:

// 获取 id 为 time 的第一个元素
var timer = document.getElementById('time');
// 返回获取到的整个元素标签
console.log(timer);
// 返回获取到的元素类型
console.log(typeof timer);
// 在控制台中显示指定 JavaScript 对象的属性,并通过类似文件树样式的交互列表显示, 更好的查看属性和方法
console.dir(timer);

通过标签名获取 getElementByTagName()

  • 此方法为 DOM 老 API,兼容性好,但是不推荐开发时使用。

  • 此方法将获取到的对象存放于伪数组,以伪数组的形式返回所有获取的元素。

  • 如果获取到的元素只有一个,依然返回伪数组;如果没有获取到元素,返回的是一个空的伪数组、

  • 语法:

// 获取页面中所有 li
var lis = document.getElementsByTagName('li');
// 输出伪数组
console.log(lis);
// 输出伪数组中的第2个对象
console.log(lis[1]);
// 遍历
for (i = 0; i < lis.length; i++){
	console.log(lis[i]);
}

根据类名来获取 getElementByClassName()

  • 此方法为 HTML5 新增的方法,仅仅兼容ie9+,平时不常用。
  • 此方法将获取到的对象存放于伪数组,以伪数组的形式返回所有获取的元素。
  • 如果获取到的元素只有一个,依然返回伪数组;如果没有获取到元素,返回的是一个空的伪数组。
  • 语法:
var box = document.getElementsByClassName('box');
console.log(box);

根据选择器获取 querySelector()

  • 此方法为 HTML5 新增的方法,仅仅兼容ie9+,推荐使用。
  • 此方法只返回获取到的第一个元素对象。
var box = document.querySelector('.box');
console.log(box);

根据选择器获取 querySelectorAll()

  • 此方法为 HTML5 新增的方法,仅仅兼容ie9+,推荐使用。
  • 此方法将获取到的对象存放于伪数组,以伪数组的形式返回所有获取的元素。
  • 如果获取到的元素只有一个,依然返回伪数组;如果没有获取到元素,返回的是一个空的伪数组
var box =  document.querySelectorAll('.box');
console.log(box);

获取 body 和 html

  • 在文档中元素的获取中,有专门获取 body 和 html 的方法
  • 语法:
// 获取body
var body = document.body;
console.log(body);
console.dir(body);
// 获取整个html
var htmlEle = document.documentElement;
console.log(htmlEle);

事件操作

网页中的每个元素都可以产生某些可以触发 JS 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作

事件有三部分组成:事件源、事件类型、事件处理程序,我们将其称为事件三要素

  1. 事件源:事件的触发对象(谁触发了事件?)
  2. 事件类型:事件如何被触发 什么事件 比如鼠标点击(onclick)还是鼠标经过 还是键盘按下
  3. 事件处理程序:事件被触发要执行的操作

注册事件

给元素添加事件,称为注册事件或者绑定事件

注册事件有两种方式:传统方式方法监听注册方式

  1. 传统注册方式

    • 使用 on 开头的事件 onclick

    • <button onclick="alert('hi')"></button>

    • btn.onclock = function(){}

    • 特点:注册事件的唯一性

    • 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数。

  2. 监听注册方式

    • w3c 标准 推荐方式

    • addEventListener() 他是一个方法

    • IE9之前的IE版本不支持此方法,可以使用attachEvent() 代替

    • 特点:同一个元素同一个事件可以注册多个监听器

传统方式注册事件

事件描述
onclick点击事件
onfocus获得焦点事件
onblur失去焦点事件
onmouseover鼠标经过
onmouseout鼠标离开
onmousemove鼠标移动
onmouseup鼠标弹起
onmousedown鼠标按下

语法:

// 获取按钮元素
var btn = document.querySelector('button');
// 给按钮元素添加点击事件
btn.onclick = function(){
    // 事件处理程序,但被点击时执行
    console.log('按钮被点击');
}

addEventListener 事件监听方式

eventTarget.addEventListener(type, listener, useCapture)

eventTarget.addEventListener() 方法将指定的监听器注册到 evenTarget (目标对象) 上,当该对象触发指定事件时,就会执行事件处理函数。

该方法有三个参数:

  • type:事件类型字符串,比如 click、mouseover,注意这里并没有on
  • listener:事件处理函数,事件发生时,会调用该监听函数
  • useCapture:事件流,默认为false。flase为冒泡阶段,true为捕获阶段。

代码实例:

// 给元素btn添加两个监听鼠标点击事件
btn.addEvenListener('click',function(){
    alert(22);
})
btn.addEvenListener('click',function(){
    alert(33);
})

attachEvent 事件监听方式

eventTarget.attachEvent(type, callback)

该方法将指定的监听器注册到指定的对象上,当对象被触发,就会执行指定的回调函数。

该方法只支持ie9之前的ie浏览器,并不被其他浏览器支持。

  • type:事件类型字符串,比如 onclick、onmouseover,这里要带有 on
  • callback:事件处理函数,当目标触发事件时回调函数被调用

代码实例:

btn.attachEvent('onclick', function(){
    alert(11)
})

对不同浏览器的兼容性处理

这里写一个兼容性函数,来适配不同浏览器的兼容性问题(PS:IE就是个毒瘤)

兼容性要首先照顾大多数浏览器,再处理特殊浏览器

function addEventListener(element, eventName, fn){
	// 判断当前浏览器是否支持 addEventListener
    if(element.addEvenListener){
        element.addEventListener(eventName, fn);
    }else if(element.attachEvent){
        element.attachEvent('on' + eventName, fn);
    }else{
        // 相当于 element.onclick = fn
        element['on' + eventName] = fn;
    }
}

删除事件(解绑事件)

传统方式删除事件

直接给指定的对象的相应的事件赋值为null,即可删除该事件。

eventTarget.onclick = null;

监听方式删除事件 removeEventListener

eventTarget.removeEventListener(type, listener, useCapture)
  • type:事件类型字符串,比如 click、mouseover,注意这里并没有on

  • listener:需要解绑的事件处理函数

  • useCapture:事件流,默认为false。flase为冒泡阶段,true为捕获阶段。

代码实例:

btn.addEventListener('click', fn);
function fn() {
	alert(22);
    btn.removeEventListener('click', fn);
}

注意:如果要删除监听事件,那么添加监听事件时一定要用具体的函数名,不能使用匿名函数。使用匿名函数时,再删除事件时候,无法指定事件触发函数。

监听方式删除事件 detachEvent

此方法对应 attackEvent

eventTarget.detachEvent(type, callback)
  • type:事件类型字符串,比如 onclick、onmouseover,这里要带有 on
  • callback:要删除的事件处理函数

代码实例:

btn.attachEvent('onclick', fn);
function fn() {
	alert(33);
    btn.detachEvent('onclick', fn);
}

对不同浏览器的兼容性处理

function removeEventListener(element, eventName, fn){
	// 判断当前浏览器是否支持 removeEventListener
    if(element.removeEvenListener){
        element.removeEventListener(eventName, fn);
    }else if(element.detachEvent){
        element.detachEvent('on' + eventName, fn);
    }else{
        // 相当于 element.onclick = fn
        element['on' + eventName] = null;
    }
}

DOM 事件流

事件流描述的是从页面接收事件的顺序

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程称为 DOM 事件流。

DOM 事件流分为3个阶段:

  1. 捕获阶段
  2. 当前目标阶段
  3. 冒泡阶段

事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到 DOM 最顶层节点的过程。

事件捕获:网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程。

代码验证

  1. JS 代码只能执行捕获或者冒泡的其中一个阶段。
  2. onclick 和 attachEvent 只能得到冒泡阶段。
  3. addEventListener中的第三个参数如果是 true,表示再事件捕获阶段调用事件处理程序;如果是false(不写默认时false)则表示再事件冒泡阶段调用事件处理程序。

演示地址

<!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>事件流</title>
    <style>
        .father {
            width: 300px;
            height: 300px;
            margin: 10px auto;
            background-color: antiquewhite;
            overflow: hidden;
        }

        .son {
            width: 200px;
            height: 200px;
            margin: 50px auto;
            background-color: aliceblue;
        }
    </style>
</head>

<body>
    <div class="father">father
        <div class="son">
            son 冒泡阶段 触发事件处理程序
        </div>
    </div>
    <div class="father">father2
        <div class="son">
            son2 捕获阶段 触发事件处理程序
        </div>
    </div>
    <script>
        var son = document.querySelectorAll('.son');
        // 指定事件在冒泡阶段触发事件处理程序
        son[0].addEventListener('click', function () {
            alert('son');
        })
        son[0].parentNode.addEventListener('click', function () {
            alert('fatehr');
        })

        // 指定事件在捕获阶段触发事件处理程序
        son[1].addEventListener('click', function () {
            alert('son');
        }, true)
        son[1].parentNode.addEventListener('click', function () {
            alert('fatehr');
        }, true)
    </script>
</body>

</html>

事件对象

事件对象只有有了事件才会存在,他是系统给我们自动创建的,不需要我们传递参数。

事件对象是我们事件的一系列的相关数据的集合,跟事件相关的,比如鼠标点击里面就包含了鼠标的相关信息,如鼠标坐标等。如果是键盘事件,那么里面就包含的键盘事件的信息,比如判断用户按下了哪个键。

事件对象可以由我们自己命名,比如 event、evt、e。

对 ie678 有兼容性问题,ie678 不可自己对事件对象命名,只能使用window.event

代码:

div.onclick = function(event) {
	console.log(event);
}

兼容性处理:

div.onclick = function(e) {
	e = e || window.event;
    console.log(e);
}

常见事件对象的属性和方法

属性描述
e.target返回触发事件的对象 不兼容ie678
this返回的是绑定事件的对象
e.srcElement返回触发事件的对象 兼容ie678
e.currentTarget和this相似 但是不兼容ie678
e.type返回事件的类型,比如 click、mouseover 不带on
e.cancelBubbel阻止冒泡 ie678不兼容
e.returnValue阻止默认事件(默认行为)非标准 比如不让链接跳转 ie678不兼容
e.preventDefault()阻止默认事件(默认行为)标准
e.stopPropagation()阻止冒泡 标准

this 和 target

如果我们有一个 ul>li,给 ul 绑定一个点击事件。

那么当我们点击 li 的时候:

e.target 返回的是触发事件的对象,也就是 li,e.target 不兼容ie678

this 返回的是绑定事件的对象,也就是 ul

对于这两个方法我们还有两个额外的相似的方法:

e.srcElement 对应 e.target,但是前者兼容了 ie678

e.currentTarget 对应 this,但是前者不兼容ie678

阻止默认行为

有些标签默认就带有一些行为,比如 a 链接跳转等,我们可以使用如下方法阻止其默认行为。

阻止行为的方法有两种:

  • e.preventDefault():标准的阻止默认事件方法,推荐使用,但是不兼容ie678
  • e.returnValue:这是一个属性,兼容ie678。
  • return false:这种方法也可以阻止默认事件,而且没有兼容性问题。需要注意的是,用这种方法后,return之后的代码将不会执行。
a.onclick = function(e) {
    e.preventDefault();
    e.returnValue;
    return false;
}

阻止冒泡(重点)

我们已经知道 dom 事件流包括:捕获,目标,冒泡三个阶段。

事件开始冒泡时,事件将会由具体的目标元素向上逐级传递到dom最顶层节点。

阻止冒泡就是阻止事件向上传播。

阻止冒泡的方法有两种:

  • e.stopPropagation():标准阻止冒泡的方法,推荐使用,但是不兼容ie678
  • e.cancelBubbel:这是一个属性,用于阻止冒泡,兼容ie678
div.onclick = function(e) {
    e.stopPropagation();
    e.cancelBubbel = True;
}

事件委托

事件委托也称为事件代理,在jQuery里面也叫事件委派。

其思想就是,当一个父节点中的所有子节点都需要点击事件时,我们不是给每个子节点单独设置事件监听器,而是将事件监听器设置到父亲节点上,然后利用冒泡原理来影响每个子节点,这样点击子节点就可以触发父节点的监听器。

这样我们只需要操作一次DOM,提高了程序的性能。

<body>
    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
    <script>
    	var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            e.target.style.backgroundColor = 'pink';
        })
    </script>
</body>

常用的鼠标事件

禁止鼠标右键菜单(contextmenu)

contextmenu 主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单。

document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
})

禁止鼠标选中(selectstart 开始选中)

document.addEventListener('selectstart', function(e) {
    e.preventDefault();
})

鼠标事件对象

event 对象代表了事件的状态,跟事件相关的一些列信息的集合。其中就包裹键盘事件信息和鼠标事件信息。鼠标事件对象是 MouseEvent;键盘事件对象是 KeyboardEvent。

鼠标事件对象描述
e.clientX返回鼠标相对于浏览器窗口可视区的 X 坐标
e.clientY返回鼠标相对于浏览器窗口可视区的 Y 坐标
e.pageX返回鼠标相对于文档页面的 X 坐标 IE9+支持
e.pageY返回鼠标相对于文档页面的 Y 坐标 IE9+支持
e.screenX返回鼠标相对于电脑屏幕的 X 坐标
e.screenY返回鼠标相对于电脑屏幕·的 Y 坐标

常用的键盘事件

键盘事件描述
onkeyup某个键盘按键被松开时触发
onkeydown某个键盘按键被按下时触发
onkeypress某个键盘按键被按下时触发 但是这个方法不识别功能键,比如 ctrl shift等

当三个事件同时存在时,执行顺序永远为:keydown --> keypress --> keyup

键盘事件对象

事件对象描述
key记录用户按下的键盘按键,除了ie678,还有些其他浏览器不兼容
keyCode记录用户按下键的 ASCLL 值

操作元素

JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容、属性等。

改变元素内容

innerText

  • innerText 只获取元素中的文本内容
  • innerText 会删除空格和换行,只保留文本

​ 语法:

var div = document.querySelector('div');
div.innerText = 'brokyz'

innerHTML

  • innerHTML 会保留空格和换行
  • innerHTML 修改时支持 HTML 标签,在内容中添加标签将会被识别
  • 推荐使用 innerHTML
var div = document.querySelector('div');
div.innerHTML = '<strong>brokyz</strong>'

修改或添加属性内容

  • 当获取到元素时,我们对元素中的属性进行添加和更改。
  • 本方法对 html 中已经有定义的属性进行操作
  • 修改属性时会直接覆盖掉原来的属性值。

语法:

// 获取a标签
var a = document.querySelector('a');
// 更改或添加a的属性
a.href = 'https://bilibili.com';
a.id = 'bilibili';
// 修改类名属性值
a.className = 'iama';

表单元素的属性操作

利用 DOM 可以操作如下表单元素属性:

type、value、checked、selected、disabled

修改或添加CSS样式属性

  • 我们可以通过 JS 修改元素的大小、颜色、位置等 CSS 样式。
  • JS 里面的样式采用驼峰命名法,比如 fontSize、backgroundColor
  • JS 修改 style 样式操作,产生的是行内样式,修改后的 CSS 权重更高

语法:

var div = document.querySelector('div');
this.style.backgroundColor = 'antiquewhite';
this.style.width = '400px';

使用 className 修改元素类名的方式修改CSS样式属性

  • 使用 className 修改样式属性会直接覆盖掉原来的 class 值
<!DOCTYPE html>
<head>
    <style>
        .text {
            width: 400px;
            height: 400px;
            background-color: antiquewhite;
        }

        .change {
            background-color: aliceblue;
        }
    </style>
</head>

<body>
    <div class=”text“>文本</div>
    
    <script>
        var div = document.querySelector('div');
        div.onclick = function(){
            // 此方法会直接覆盖掉原来class属性中的text
            this.className = 'change';
            // 如果不覆盖原来的class属性,只是追加的话可以这样使用
            this.className += ' change';
        }
    </script>
</body>
</html>

对自定义属性值的操作

  • 在标签中,有些属性是内置的,比如 a标签的hreftarget等,这些都可以直接获取元素a,然后使用a.href对属性进行操作。
  • 在标签中,也有些属性是我们自定义的,比如我们自己给a标签定义一个index = '1',这时我们就不能使用a.index对自定义属性进行操作。
  • 以下我们将讲解对自定义属性的操作方法:

获取自定义属性值 getAttribute()

  • getAttribute()既可以获取自定义的属性值,也可以获取自带的属性值。

语法:

var div = document.querySelector('div');
// 获取内置属性值
console.log(div.getAttribute('id'));
// 获取自定义属性值
console.log(div.getAttribute('index'));

添加和修改自定义属性值

  • div.setAttribute('自定义属性','要修改的值');既可以修改自定义的属性值,也可以修改自带的属性值。
  • 但是用div.setAttribute('自定义属性','要修改的值')修改元素的类名时,只需要指定class即可,不需要自带方法那样使用className

语法:

var div = document.querySelector('div');
div.setAttribute('index','2');
div.setAttribute('class','box');
  • 当使用setAttribute设置 class 时就是使用 class 而不是使用 className

移除自定义属性值

  • div.removeAttribute()既可以删除自定义的属性值,也可以删除自带的属性值。

语法:

div.removeAttribute('index');

H5自定义属性新规范

由于自定义属性,无法使用自带的方法div.index调用,所以html5新增了对自定义属性的调用支持

  • h5标准要求在自定义属性前加data-,当调用的时候使用dataset调用
  • 当自定义属性中有多个 - 连接时,调用时需要使用驼峰命名法调用
  • 此方法存在兼容性问题,使用 dataset 获取时,仅对ie11+支持

语法:

<body> 
	<div data-listname="123" data-list-name="456"></div>
	<script>
		var div = document.querySelector('div');
		console.log(div.dataset.listname);
		console.log(div.dataset.listName);
	</script>
</body>

节点操作

节点操作可以利用层级关系获取元素,为我们开发提供了一种更加方便的获取元素的方法。

节点概述

网页中的所有内容都是节点(标签、属性、文本、注释等),在 DOM 中,节点使用 node 来表示。

HTML DOM树中的所有节点均可以通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。

一般地,节点至少拥有node Type(节点类型)、nodeName(节点名称)和 nodeValue(节点值)这三个基本属性。

  • 元素节点 nodeType 为 1
  • 属性节点 nodeType 为 2
  • 文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)

实际开发中,节点操作主要操作的是元素节点

节点的使用

代码使用频率描述
ul.parentNode常用获取父亲节点,如果找不到返回空
ul.childNodes不常用得到所有子节点,包含 元素节点 文本节点等等
ul.children常用获取所有的子元素节点 实际开发常用
ul.firstChild不常用获取第一个子节点,不管是文本节点和元素节点都可以被拿到
ul.lastChild不常用获取最后一个子节点,不管是文本节点和元素节点都可以被拿到
ul.firstElementChild常用获取第一个元素节点,仅支持ie9+
ul.lastElementChild常用获取最后一个元素节点,仅支持ie9+
li.nextSibling不常用返回下一个兄弟节点 包含 元素节点 文本节点等等
ul.nextElementSibling常用返回下一个元素兄弟节点,仅支持ie9+
ul.previousSibling不常用返回上一个兄弟节点 包含 元素节点 文本节点等等
ul.previousElementSibling常用返回上一个元素兄弟节点,仅支持ie9+
        // 1.父节点 parentNode
        var erweima = document.querySelector('.erweima');
        console.log(erweima.parentNode); // 如果找不到父节点就返回为空

        // 2.子节点 childNodes (集合) 得到所有子节点,包含 元素节点 文本节点等等
        var ul = document.querySelector('ul');
        console.log(ul.childNodes);
        // 注意:返回值里面包含了所有的子节点
        // 如果只想获得里面的元素节点,则需要专门处理。所以我们一般不提倡使用childNodes
        for (let i = 0; i < ul.childNodes.length; i++) {
            const element = ul.childNodes[i];
            if (element.nodeType == 1){
                console.log(element);
            }
        }

        // children 获取所有的子元素节点 实际开发常用
        console.log(ul.children);

        // firstchild 获取第一个子节点,不管是文本节点和元素节点都可以被拿到
        console.log(ul.firstChild);
        // lastchild 获取最后一个子节点,不管是文本节点和元素节点都可以被拿到
        console.log(ul.lastChild);
        
        // firstElementChild 获取第一个元素节点
        console.log(ul.firstElementChild);
        // lastElementChild 获取最后一个元素节点
        console.log(ul.lastElementChild);
        // 注意:这几个返回第一个和最后一个存在兼容性问题,不支持ie9
        // 实际开发中,兼顾兼容性
        console.log(ul.children[0]);

        // 3.兄弟节点
        // nextSibling 返回下一个兄弟节点 包含 元素节点 文本节点等等
        console.log(ul.nextSibling);
        // nextElement 返回下一个元素兄弟节点
        console.log(ul.nextElementSibling);
        // prevousSibling 返回上一个兄弟节点 包含 元素节点 文本节点等等
        console.log(ul.previousSibling);
        // prevousElementSibling 返回上一个兄弟节点 包含 元素节点 文本节点等等
        console.log(ul.previousElementSibling);

创建节点并添加节点

代码描述
ul.appendChild()在孩子的最后面添加元素
ul.insertBefore(要添加的元素,指定的孩子元素)在指定孩子元素的前面添加要添加的元素

语法:

var li = document.createElement('li');
var ul = document.querySelector('ul');
// 在ul的孩子后面追加元素
ul.appendChild(li);
// 在ul的指定孩子前面插入元素
ul.insertBefore(li,ul.children[0])

删除节点

var ul = document.querySelector('ul');
// 删除父节点里面的孩子
ul.removeChild(ul.children[0]); // 删除ul中的第一个孩子

复制节点

var ul = document.querySelector('ul');
//复制节点
var cloned = ul.children[0].cloneNode(true); //括号为空或者false,是浅拷贝, 则只复制标签不复制内容,如果为true,复制内容,深拷贝
ul.appendChild(cloned);

三种创建元素方式的区别

  • document.write()

    • document.write('<div>123<div>')文档执行完毕,他会导致页面全部重绘
  • innerHTML = ‘ ’

    • div.innerHTML += '<div>123<div>'使用拼接的方式创建多个元素时,耗时非常大
    • 当将要创建的元素插入数组中,再通过innerHTML插入时,效率大大提成,为最优
  • document.createElement()

    • 使用这种方法创建,并使用节点操作添加到页面中时,方法效率高,但是没有innerHTML结合数组的形式效率高

    实验: 测试地址

<!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>三种创建元素的区别</title>
</head>

<body>
    <button>文档流执行完毕,测试document.write</button>
    <button>测试innerHTML执行效率</button>
    <button>测试innerHTML结合数组执行效率</button>
    <button>测试creatElement执行效率</button>
    <div class="test"></div>
    <script>
        // document.write 当所有文档流执行完毕时,执行这段代码会导致页面重绘
        var btn = document.querySelectorAll('button');
        btn[0].onclick = function () {
            document.write('<div>当所有文档流执行完毕时,执行这段代码会导致页面重绘 document.write</div>');
        }


        // 测试innerHTML执行效率
        var test = document.querySelector('.test');
        btn[1].onclick = function () {
            if (test.children[0]) {
                test.removeChild(test.children[0]);
            }
            var div = document.createElement('div');
            var d1 = +new Date();
            for (var i = 0; i < 2000; i++) {
                div.innerHTML += "<div style='width:100px;border:1px solid blue;'></div>"
            }
            var d2 = +new Date();
            console.log(d2 - d1);
            test.appendChild(div);

        }

        // 测试innerHTML加数组效率
        btn[2].onclick = function () {
            if (test.children[0]) {
                test.removeChild(test.children[0]);
            }

            var div = document.createElement('div');
            var d1 = +new Date();
            var arr = [];
            for (var i = 0; i < 2000; i++) {
                arr.push("<div style='width:100px;border:1px solid blue;'></div>");
            }
            div.innerHTML = arr.join('');
            test.appendChild(div);
            var d2 = +new Date();
            console.log(d2 - d1);


        }

        // creatElement效率测试
        btn[3].onclick = function () {
            if (test.children[0]) {
                test.removeChild(test.children[0]);
            }
            var div = document.createElement('div');
            var d1 = +new Date();
            // 注意创建要添加的元素一定要写在循环内,因为如果写在外面,只创建一次,append添加之后就没有了。
            for (var i = 0; i < 2000; i++) {
                var divs = document.createElement('div');
                divs.style.border = '1px solid blue';
                divs.style.width = '100px';
                div.appendChild(divs);
            }
            var d2 = +new Date();
            test.appendChild(div)
            console.log(d2 - d1);
        }
    </script>
</body>
</html>

DOM 重点核心(复习)

DOM 就是文档对象模型(Document Object Model),是w3c组织推荐的处理可拓展标记语言(HTML或者XML)的标准编程接口。

W3C已经定义了一系列的 DOM 接口,通过这些接口 DOM 接口可以改变网页的内容、结构和样式。

  1. 对于 JavaScript,为了能够使 JavaScript 操作 HTML,JavaScript就有了一套自己的 DOM 编程接口。
  2. 对于 HTML,DOM 使得 HTML 形成了一棵 DOM 树。其中包含了文档(整个页面)、元素(页面中所有的标签)、节点(页面中所有的内容,文档是节点,元素是节点,属性也是节点)。
  3. 我们获取来的 DOM 元素是一个对象(object),所以称为文档对象模型。

关于 DOM 操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。

创建

  1. document.write
  2. innerHTML
  3. createElement

  1. appendChild
  2. insertBefore

  1. removeChild

主要是修改 DOM 元素的属性、内容、表单值等

  1. 修改元素属性:src、href、title等
  2. 修改普通元素内容:innerHTML、innerText
  3. 修改表单元素:value、type、disable等
  4. 修改元素样式:style、className

主要获取查询 DOM 元素

  1. DOM 提供的 API 方法:getElementById、getElementByTagName 古老用法,不推荐
  2. H5 提供的新方法:querySelector、querySelectorAll 推荐
  3. 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)推荐

属性操作

主要针对于自定义属性

  1. setAttribute:设置dom的属性值
  2. getAttribute:得到dom的属性值
  3. removeAttribute:移除属性

事件操作

给元素注册事件、采取事件源.事件类型 = 事件处理程序

  1. onclick:鼠标点击左键触发
  2. onmouseover:鼠标经过触发
  3. onmouseout:鼠标离开触发
  4. onfocus:获得鼠标焦点触发
  5. onblur:失去鼠标焦点触发
  6. onmousemove:鼠标移动触发
  7. onmouseup:鼠标弹起触发
  8. onmousedown:鼠标按下触发

版权声明:本文为weixin_45834168原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。