节点概述

网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM 中,节点使用 node 来表示。HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。
DOM节点操作 - 图1
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
DOM节点操作 - 图2

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

父节点

node.parentNode

  • 返回某节点的父节点,最近的一个父节点
  • 如果没有父节点,则返回null

image.png

子节点

parentNode.childNodes

  • 返回指定节点的子节点的集合,会即时更新
  • 会返回所有的节点(包含元素节点、文本节点等)

image.png

parentNode.children

  • 只读属性
  • 只返回元素节点
  • 非标准,但是各个浏览器都支持

image.png
image.png

parent.firstChild

image.png

  • 返回第一个子节点,找不到返回null,包含所有节点

    parent.lastChild

  • 返回最后一个子节点,找不到返回null,包含所有节点

    parent.firstElementChild

  • 返回第一个子元素节点,找不到返回null

  • IE9以上支持

    parent.lastElementChild

  • 返回最后一个子元素节点,找不到返回null

  • IE9以上支持

    首末节点兼容方案

    实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和 lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?

image.png

兄弟节点

下一个兄弟节点
DOM节点操作 - 图9
上一个兄弟节点
DOM节点操作 - 图10

  1. <div>我是div</div>
  2. <span>我是span</span>
  3. <script>
  4. var div = document.querySelector('div');
  5. // 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
  6. console.log(div.nextSibling);
  7. console.log(div.previousSibling);
  8. // 2. nextElementSibling 得到下一个兄弟元素节点
  9. console.log(div.nextElementSibling);
  10. console.log(div.previousElementSibling);
  11. </script>

下一个兄弟元素节点(有兼容性问题)
DOM节点操作 - 图11
上一个兄弟元素节点(有兼容性问题)
DOM节点操作 - 图12
DOM节点操作 - 图13
DOM节点操作 - 图14

  1. function getNextElementSibling(element) {
  2. var el = element;
  3. while (el = el.nextSibling) {
  4. if (el.nodeType === 1) {
  5. return el;
  6. }
  7. }
  8. return null;
  9. }

创建结点

document.createElement()

  • document.createElement(‘tagName’)
  • 动态创建元素节点

    node.cloneNode()

    DOM节点操作 - 图15
    1. <ul>
    2. <li>1111</li>
    3. <li>2</li>
    4. <li>3</li>
    5. </ul>
    6. <script>
    7. var ul = document.querySelector('ul');
    8. // 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
    9. // 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
    10. var lili = ul.children[0].cloneNode(true);
    11. ul.appendChild(lili);
    12. </script>

    Demo:动态生成表格

    DOM节点操作 - 图16
    DOM节点操作 - 图17
    1. <script>
    2. // 1.先去准备好学生的数据
    3. var datas = [{
    4. name: '魏璎珞',
    5. subject: 'JavaScript',
    6. score: 100
    7. }, {
    8. name: '弘历',
    9. subject: 'JavaScript',
    10. score: 98
    11. }, {
    12. name: '傅恒',
    13. subject: 'JavaScript',
    14. score: 99
    15. }, {
    16. name: '明玉',
    17. subject: 'JavaScript',
    18. score: 88
    19. }, {
    20. name: '大猪蹄子',
    21. subject: 'JavaScript',
    22. score: 0
    23. }];
    24. // 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行
    25. var tbody = document.querySelector('tbody');
    26. // 遍历数组
    27. for (var i = 0; i < datas.length; i++) {
    28. // 1. 创建 tr行
    29. var tr = document.createElement('tr');
    30. tbody.appendChild(tr);
    31. // 2. 行里面创建单元格td 单元格的数量取决于每个对象里面的属性个数
    32. // 使用for in遍历学生对象
    33. for (var k in datas[i]) {
    34. // 创建单元格
    35. var td = document.createElement('td');
    36. // 把对象里面的属性值 datas[i][k] 给 td
    37. td.innerHTML = datas[i][k];
    38. tr.appendChild(td);
    39. }
    40. // 3. 创建有删除2个字的单元格
    41. var td = document.createElement('td');
    42. td.innerHTML = '<a href="javascript:;">删除 </a>';
    43. tr.appendChild(td);
    44. }
    45. // 4. 删除操作 开始
    46. var as = document.querySelectorAll('a');
    47. for (var i = 0; i < as.length; i++) {
    48. as[i].onclick = function() {
    49. // 点击a 删除 当前a 所在的行(链接的爸爸的爸爸) node.removeChild(child)
    50. tbody.removeChild(this.parentNode.parentNode)
    51. }
    52. }
    53. </script>

    创建元素的三种方式对比

    DOM节点操作 - 图18
    1. <script>
    2. // 三种创建元素方式区别
    3. // 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘
    4. var btn = document.querySelector('button');
    5. btn.onclick = function() {
    6. document.write('<div>123</div>');
    7. }
    8. // 2. innerHTML 创建元素
    9. var inner = document.querySelector('.inner');
    10. for (var i = 0; i <= 100; i++) {
    11. inner.innerHTML += '<a href="#">百度</a>'
    12. }
    13. var arr = [];
    14. for (var i = 0; i <= 100; i++) {
    15. arr.push('<a href="#">百度</a>');
    16. }
    17. inner.innerHTML = arr.join('');
    18. // 3. document.createElement() 创建元素
    19. var create = document.querySelector('.create');
    20. for (var i = 0; i <= 100; i++) {
    21. var a = document.createElement('a');
    22. create.appendChild(a);
    23. }
    24. </script>

    innerTHML和createElement效率对比

innerHTML字符串拼接方式(效率低)

  1. <script>
  2. function fn() {
  3. var d1 = +new Date();
  4. var str = '';
  5. for (var i = 0; i < 1000; i++) {
  6. document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>';
  7. }
  8. var d2 = +new Date();
  9. console.log(d2 - d1);
  10. }
  11. fn();
  12. </script>

createElement方式(效率一般)

  1. <script>
  2. function fn() {
  3. var d1 = +new Date();
  4. for (var i = 0; i < 1000; i++) {
  5. var div = document.createElement('div');
  6. div.style.width = '100px';
  7. div.style.height = '2px';
  8. div.style.border = '1px solid red';
  9. document.body.appendChild(div);
  10. }
  11. var d2 = +new Date();
  12. console.log(d2 - d1);
  13. }
  14. fn();
  15. </script>

innerHTML数组方式(效率高)

  1. <script>
  2. function fn() {
  3. var d1 = +new Date();
  4. var array = [];
  5. for (var i = 0; i < 1000; i++) {
  6. array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>');
  7. }
  8. document.body.innerHTML = array.join('');
  9. var d2 = +new Date();
  10. console.log(d2 - d1);
  11. }
  12. fn();
  13. </script>

插入结点

node.appendChild()

  • node.appendChild(child)
  • 添加到父节点的子节点列表末尾

    node.insertBefore()

  • node.insertBefore(child,指定元素)

  • 将一个节点添加到父节点的指定子节点前面

image.png

Demo:简单版发布留言

DOM节点操作 - 图20
DOM节点操作 - 图21

  1. <body>
  2. <textarea name="" id=""></textarea>
  3. <button>发布</button>
  4. <ul>
  5. </ul>
  6. <script>
  7. // 1. 获取元素
  8. var btn = document.querySelector('button');
  9. var text = document.querySelector('textarea');
  10. var ul = document.querySelector('ul');
  11. // 2. 注册事件
  12. btn.onclick = function() {
  13. if (text.value == '') {
  14. alert('您没有输入内容');
  15. return false;
  16. } else {
  17. // console.log(text.value);
  18. // (1) 创建元素
  19. var li = document.createElement('li');
  20. // 先有li 才能赋值
  21. li.innerHTML = text.value;
  22. // (2) 添加元素
  23. // ul.appendChild(li);
  24. ul.insertBefore(li, ul.children[0]);
  25. }
  26. }
  27. </script>
  28. </body>

删除节点

node.removeChild()

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

image.png

Demo:删除留言

DOM节点操作 - 图23
DOM节点操作 - 图24

  1. <textarea name="" id=""></textarea>
  2. <button>发布</button>
  3. <ul>
  4. </ul>
  5. <script>
  6. // 1. 获取元素
  7. var btn = document.querySelector('button');
  8. var text = document.querySelector('textarea');
  9. var ul = document.querySelector('ul');
  10. // 2. 注册事件
  11. btn.onclick = function() {
  12. if (text.value == '') {
  13. alert('您没有输入内容');
  14. return false;
  15. } else {
  16. // console.log(text.value);
  17. // (1) 创建元素
  18. var li = document.createElement('li');
  19. // 先有li 才能赋值
  20. li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
  21. // (2) 添加元素
  22. // ul.appendChild(li);
  23. ul.insertBefore(li, ul.children[0]);
  24. // (3) 删除元素 删除的是当前链接的li 它的父亲
  25. var as = document.querySelectorAll('a');
  26. for (var i = 0; i < as.length; i++) {
  27. as[i].onclick = function() {
  28. // 删除的是 li 当前a所在的li this.parentNode;
  29. ul.removeChild(this.parentNode);
  30. }
  31. }
  32. }
  33. }
  34. </script>