Loading...
墨滴

CYF

2021/04/24  阅读:56  主题:默认主题

DOM之节点操作

img
img

1、节点

页面中所有内容都是节点:标签、属性、文本、注释等,在DOM中,节点用node来表示

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

img

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

  • 元素节点 nodeType 为 1
  • 属性节点 nodeType 为 2
  • 文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)
<div id="you">你能不能温柔提醒</div>
  • 元素节点:<div></div>
  • 属性节点:id='you'
  • 文本节点:你能不能温柔提醒

2、节点层级

img
img

利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系

2.1 父节点

node.parentNode

栗子:

<div class="parent">
    <div class="son"></div>
</div>
let son = document.querySelector('.son');
// 获取最近一级的父元素,如果找不到父节点就返回null
console.log(son.parentNode);

2.2 子节点

parentNode.childNodes;      
  • 标准
  • 返回包含指定节点的集合,该集合为即使更新的集合

返回值里面包含了所有的子节点,包括元素节点、文本节点等

let parent = document.querySelector('.parent');
console.log(parent.childNodes);  // [text, div.son, text]
  • text 是换行
  • 如果想要获取里面的元素,需要在过滤一遍,所以一般不使用 childNodes

过滤元素节点

for (var i = 0; i < box.childNodes.length; i++) {
    // 过滤掉文本节点
    if (box.childNodes[i] === 1) {
        console.log(box.childNodes[i]);
    }
}

parentNode.children

  • 是一个只读属性,返回所有的子元素节点,其余节点不返回
  • 非标准

虽然 children 是一个非标准,但是得到各浏览器的支持,因此我们可以放心使用

let parent = document.querySelector('.parent');
console.log(parent.children); // [div.son]

获取第n个节点

firstChild 返回的是第一个子节点,找不到则返回null。同样,也是包含所有的节点

parentNode.firstChild    // 获取第一个子节点

firstChild 返回的是最后一个子节点,找不到则返回null。同样,也是包含所有的节点

parentNode.lastChild    // 获取最后一个子节点

栗子:

<ul>
    <li>1</li>
    <li>2</li>
</ul>
var ul = document.querySelector('ul');
console.log(ul.firstChild); // #text
console.log(ul.lastChild); // #text

但是上面两个获取到的是 文本节点

但是,我们可以用以下的方法:

// 获取第一个子节点
parentNode.firstElementChild;
// 获取最后一个子节点
parentNode.firstElementChild;

注意:这两个方法有兼容性问题,IE9 以上才支持

所以,为了解决兼容新问题和返回第n个子节点的做法,我们直接使用children

console.log(ul.children[0]); // <li>1</li>

console.log(ul.children[1]); // <li>2</li>

总结:

  1. parentNodeparentElement功能一样,childNodeschildren功能一样
  2. parentNodechildNodes 是符合W3C标准的,可以说比较通用。而另外两个只是IE支持,不是标准,Firefox就不支持。
  3. 我们一般使用parentNodechildren

2.3 兄弟节点

nextSibling 返回当前元素的下一个兄弟节点,找不到,找不到则返回 null ,同样,也是包含所有的节点

node.nextSibling

previousSibling 返回当前元素的上一个兄弟节点,找不到,找不到则返回 null ,同样,也是包含所有的节点

node.previousSibling

只获取元素节点

node.nextElementSibling  // 获取下一个元素
node.previousElementSibling   // 获取上一个元素
  • 这两个方法都有兼容性,IE9以上的才支持

栗子:

<div>我是div</div>
<span>我是span</
span>
var div = document.querySelector('div');
// nextSibling 获取的是换行符 即文本节点
console.log(div.nextSibling); // #text
console.log(div.previousSibling); // text

// nextElementSibling 获取元素
console.log(div.nextElementSibling); // <span>我是span</span>
console.log(div.previousElementSibling);  // null

解决兼容性问题:封装一个函数

function getNextElementSibling(element{
    let el = element
    while (el = el.nextSibling) {
        if (el.nodeType === 1) {
            return el
        }
    }
}

3、创建和添加节点

img
img

创建节点

document.createElement('tagName');
  • document.createElement() 方法创建有 tagName 指定的HTML元素,因为这些元素先不存在,是根据我们需求动态生成的,所以我们也称为 动态创建元素节点

添加元素

node.appenchild(child)   // node 是父级,child 是子级

node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。类似于 css 里面的 after 伪元素

node.insertBefore(child, 指定元素)

node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面。类似于 css 里面的 before 伪元素

栗子:

<ul>
    <li>1</li>
</ul>
// 1、创建节点元素点
var li = document.createElement("li");
// 2、添加节点
var ul = document.querySelector('ul');
ul.appendChild(li); // 添加在子节点的尾部

// 3、添加节点
var li1 = document.createElement('li');
ul.insertBefore(li1, ul.children[0]);
  • 添加节点前要先创建节点

4、删除节点

node.removeChild(child)

node.removeChild() 方法从 node 中删除一个子节点,返回删除的节点

5、复制节点

node.cloneNode()

node.cloneNode() 方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点

注意:

  1. 如果括号参数为 或者为 false,则是 “浅拷贝”;即只复制节点本身,不赋值里面的子节点
  2. 如果括号为 true,则是“深拷贝”,会复制节点本身及里面所有的子节点
let ul = document.querySelector('ul');
// 克隆 (复制)
let li = ul.children[0].cloneNode(true);
// 添加(粘贴)
ul.appendChild(li);

6、三种动态常见元素节点

img
img

6.1 document.write()

document.write() 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘

<button>按钮</button>
<div class="inner"></div>
<p class="creat"></p>
// 1、document.write()  创建元素 
document.write('<div>123</div>');

// 如果页面文档流加载完毕,在调用这句话会导致页面重绘
var btn = document.querySelector('button');
btn.onclick = function({
    document.write('<div>123</div>');
}

当我们点击按钮的时候,文档流已经加载完毕,所以会导致重绘,即页面内容会被 document.write 覆盖

  • 页面重绘就是:如果其他元素加载完毕后,document.write() 再加载(上面就是在点击按钮之后再显示),页面其他元素就会被清除掉,只显示 document.write()添加进来的元素
  • 所以实际上级开发中比较少用

6.2 innerHTML 和 ``createElement()`

  • innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
  • innerHTML 创建多个元素效率效率更高(不要拼接字符,采用数组的形式拼接),结构稍微复杂
  • createElement() 创建多个元素效率稍微低一点点,但是结构清晰
  • createElement() 常与 appendChildinsertBefore 搭配使用

CYF

2021/04/24  阅读:56  主题:默认主题

作者介绍

CYF