DOM: Document Object Model(文档对象模型)

DOM树:

image.png

回流和重绘
重绘(repaint):

当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要 UI 层面的重新像素绘制,因此损耗较少。
常见的重绘操作有:

  1. 改变元素颜色
  2. 改变元素背景色
  3. more ……

    回流(reflow):

    又叫重排(layout)。当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。
    常见的回流操作有:

  4. 页面初次渲染

  5. 浏览器窗口大小改变
  6. 元素尺寸/位置/内容发生改变
  7. 元素字体大小变化
  8. 添加或者删除可见的 DOM 元素
  9. ……

重点:回流必定会触发重绘,重绘不一定会触发回流。重绘的开销较小,回流的代价较高。

DOM 操作

1、获取元素

1.1 根据id名获取

  1. document.getElementById(idName)

1.2 根据标签名获取

  1. document.getElementsByTagName(tagName) // 返回一个集合 (类数组对象) 从整个文档获取
  2. element.getElementsByTagName(tagName) // 从element的后代元素中获取

1.3 根据类名获取(不兼容ie6~8)

  1. document.getElementsByClassName(className) // 返回一个集合(类数组对象) 从整个文档获取
  2. element.getElementsByClassName(className) // 从element的后代中获取

1.4 根据 name 属性值获取

正常的规范中,咱们只会给表单元素起name值,如果给其它元素设置name,在ie9以下版本浏览器不兼容,是获取不到的, 所以为了这种情况,咱们以后养成习惯,只给表单元素用name,非表单元素不用name

  1. document.getElementsByName() //返回集合 只有document才有该方法

1.5 根据选择器获取

注意:querySelector 和querySelectorAll 在ie6-ie8 下不兼容

  1. document.querySelector(选择器) //选择器第一个满足选择器条件的
  2. document.querySelectorAll(选择器) //选择所有满足选择器条件的,返回nodeList(类数组对象)
  3. element.querySelector(选择器)
  4. element.querySelectorAll(选择器)

1.6 document.head

  1. 获取Head元素对象

1.7 document.body

  1. 获取body元素对象

1.8 document.documentElement

获取html元素对象

2、获取一屏幕的宽度或者高度,兼容所有的浏览器

  1. // 获取一屏幕的高度
  2. var vH = document.documentElement.clientHeight || document.body.clientHeight;
  3. // 偶去一屏幕的宽度
  4. var vW = document.documentElement.clientWidth || document.body.clientWidth;

3、练习题:

获取页面中所有name属性值为 “hehe” 的元素标签

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <style>
  9. </style>
  10. </head>
  11. <body>
  12. <div class="box1">
  13. <input type="text" name="hehe">
  14. </div>
  15. <input class="box1" name="hehe">
  16. </body>
  17. </html>
  18. <script>
  19. function getElementsByName(value){
  20. var allTag=document.getElementsByTagName("*");
  21. var names=[];
  22. for(var i=0;i<allTag.length;i++){
  23. var item=allTag[i];
  24. if(item.name==value){
  25. names.push(item);
  26. }
  27. }
  28. return names;
  29. }
  30. var ary=getElementsByName("hehe")
  31. </script>

getAttribute() ====>该方法返回指定属性名的属性值。
需求:获取指定范围下所有name属性值为 “hehe” 的元素标签

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <div id="main">
  11. <div class="box1">
  12. <input type="text" name="hehe" id="input1">
  13. <div name="hehe" id="div2">111</div>
  14. </div>
  15. <input class="box1" name="hehe">
  16. </div>
  17. </body>
  18. </html>
  19. <script>
  20. var omain = document.getElementById("main");
  21. function getName(context, name, attr) {
  22. var tags = context.getElementsByTagName("*");
  23. var ary = [];
  24. for (var i = 0; i < tags.length; i++) {
  25. if (tags[i].getAttribute(name) == attr) {
  26. ary.push(tags[i])
  27. }
  28. }
  29. return ary;
  30. }
  31. var res = getName(omain, "name", "hehe");
  32. console.log(res);
  33. </script>

4、id小妙招

直接把id当成变量去用的时候,可以获取相应的id元素。(浏览器的机制)

  1. <div id="box1">111</div>
  2. <script>
  3. console.log(box1)
  4. </script>

2、节点

  • 文档节点
  • 属性节点
  • 元素节点
  • 文本节点
  • 注释节点

    2.1 文档节点

  • nodeType(节点类型):9

  • nodeName(节点名称):”#document”
  • nodeValue(节点值):null

    1. document.nodeType;
    2. document.nodeName
    3. document.nodeValue;

    2.2 属性节点

  • nodeType:2

  • nodeName:属性名
  • nodeValue:属性值

getAttributeNode() 方法从当前元素中通过名称获取属性节点。

  1. <a href="http://www.baidu.com" id="a1">百度</a>
  2. var a1=a1.getAttributeNode("href");// 获取属性节点
  3. console.log(a1.nodeType);//2
  4. console.log(a1.nodeName);//"href"; 属性名
  5. console.log(a1.nodeValue);//"http://www.baidu.com"; 属性值

image.png

2.3 元素节点

  • nodeType:1
  • nodeName:大写的标签名
  • nodeValue:null ```javascript
    百度
``` ### 2.4 文本节点 - nodeType:3 - nodeName:"#text" - nodeValue:文本内容 - 在标准浏览器中,换行和空格也属于文本节点 ```javascript 百度 var res=a1.childNodes[0]; console.log(res.nodeType);//3 console.log(res.nodeValue);//"百度"; console.log(res.nodeName);//"#text"; ``` ### 2.5 注释节点 - nodeType:8 - nodeName:"#comment" - nodeValue:注释的内容 ```javascript 百度 a1.childNodes; //NodeList(3) [text, comment, text] a1.childNodes[1].nodeName;//"#comment" a1.childNodes[1].nodeType;//8 a1.childNodes[1].nodeValue;//"a标签 " ``` ## 3、节点之间关系的属性 节点类: > parentNode 父节点 > childNodes 所有子节点的集合 > firstChild 第一个子节点 > lastChild 最后一个子节点 > previousSibling 上一个兄弟节点 > nextSibling 下一个兄弟节点 元素类: > children 所有子元素的集合 > firstElementChild 第一个子元素 IE9+ > lastElementChild 最后一个子元素 IE9+ > previousElementSibling 上一个兄弟元素 IE9+ > nextElementSibling 下一个兄弟元素 IE9+ ### 3.1 parentNode > 获取当前节点唯一的父亲节点 ```javascript
111
``` ### 3.2 childNodes > 获取当前节点所有的子节点 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.3 firstChild > 获取被选节点的第一个子节点。 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.4 lastChild > 获取被选节点的最后一个子节点。 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.5 previousSibling > 获取上一个哥哥节点 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.6 nextSibling > 获取当前节点的下一个兄弟节点 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.7 children > 获取当前元素所有的元素子节点,但是在ie6--ie8下不兼容 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.8 firstElementChild > 获取当前节点的第一个元素子节点 ie6-ie8 不兼容 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
``` ### 3.9 lastElementChild > 获取当前节点的最后一个元素子节点 ie6-ie8 不兼容 ```javascript
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!111
``` ### 3.10 previousElementSibling > 获取上一个哥哥元素节点 ie6-ie8 不兼容 ```javascript
1111
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!111
``` ### 3.11 nextElementSibling > 获取当前节点的下一个兄弟元素节点 ie6-ie8 不兼容 ```javascript
1111
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!111
``` ## 练习题 > 自己手动封装一个获取节点下面的所有子元素,要求考虑兼容性。 ```javascript 1
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
  • 选择珠峰的,都是明智的!
2
  1. > 自己手动封装一个previousElementSibling,要兼容。
  2. ```javascript
  3. <!DOCTYPE html>
  4. <html lang="en">
  5. <head>
  6. <meta charset="UTF-8">
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  8. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  9. <title>Document</title>
  10. <style>
  11. </style>
  12. </head>
  13. <body>
  14. <span id="span1">1</span>
  15. <ul id="main">
  16. <!-- 我是注释 -->
  17. <li>选择珠峰的,都是明智的!</li>
  18. <li>选择珠峰的,都是明智的!</li>
  19. <li>选择珠峰的,都是明智的!</li>
  20. <li>选择珠峰的,都是明智的!</li>
  21. </ul>
  22. <span id="span2">2</span>
  23. </body>
  24. </html>
  25. <script>
  26. function previousElmentSibling(ele){
  27. var pre=ele.previousSibling;
  28. while(pre&&pre.nodeType!==1){
  29. pre=pre.previousSibling;
  30. }
  31. return pre;
  32. }
  33. console.log(previousElmentSibling(span2))
  34. </script>

DOM 的增删改

1、createElement:创建一个元素

  1. document.createElement("div");

2、createTextNode: 创建一个文本节点

  1. var otext=document.createTextNode("哈哈!");

3、appendChild:把元素追加到一个容器的末尾

语法:[context].appendChild([元素]);

  1. <div id="id1"></div>
  2. <script>
  3. var odiv = document.createElement("div");
  4. id1.appendChild(odiv);
  5. console.log(id1)
  6. </script>

4、insertBefore: 把一个元素插入到另一个元素的前面

首先要指定一个父节点
var insertedNode = 父节点.insertBefore(要插入的节点, 插在这个节点之前)

var insertedNode = parentNode.insertBefore(newNode, referenceNode)

  • newNode:将要插入的节点
  • referenceNode:被参照的节点(即要插在该节点之前)
  • insertedNode:插入后的节点
  • parentNode:父节点

    1. <div id="id1">
    2. <p class="p1" id="p1">这是P1</p>
    3. </div>
    4. <script>
    5. var div = document.getElementById('id1');
    6. var p1 = document.getElementById('p1');
    7. var odiv = document.createElement("div");
    8. var returnDom = div.insertBefore(odiv, p1);
    9. console.log(div)
    10. </script>

    5、cloneNode:把某一个节点进行克隆

  • 【ele】.cloneNode();浅克隆: 只是克隆了一个节点,里面的内容还有样式都没克隆

  • 【ele】.cloneNode(true);深克隆:把节点包含的所有内容进行克隆

    1. <div id="id1">
    2. <p class="p1" id="p1">这是P1</p>
    3. </div>
    4. <script>
    5. var res = id1.cloneNode();
    6. var res2 = id1.cloneNode(true)
    7. console.log(res)
    8. console.log(res2)
    9. </script>

    6、removeChild:移除某个节点

    【context】.removeChild(ele);

    1. <div id="id1">
    2. 1111
    3. <p class="p1" id="p1">这是P1</p>
    4. </div>
    5. <script>
    6. id1.removeChild(p1);
    7. console.log(id1)
    8. </script>

    7、set/get/removeAttribute

    设置/获取/删除 当前元素的某一个自定义属性

  • setAttribute

  • getAttribute
  • removeAttribute
    1. box.setAttribute("index", 1);
    2. box.getAttribute("index");
    3. box.removeAttribute("index");
    4. console.log(box)
    5. // 设置
    6. // box["aa"] = 22;
    7. // 获取
    8. // box["aa"]
    9. //移除
    10. // delete box["aa"];
    基于键值对方式 增删改:修改当前对象的堆内存空间完成的(在堆内存空间可以看到)
    基于Attribute dom方法增删改,是修改html结构来完成的(此种方法设置的在结构上可以看到)
    以上两种方式不能混用