docoment object model 文档对象模型

DOM操作

【dom树】:浏览器在加载页面的时候,首先就是dom的结构计算,它形式就像是一颗大树,有很多的分支,所以被称为 “dom tree”

day 10-DOM - 图1

1.1【常见的获取DOM的方式】

  1. //ID=>submit 默认不写 docoument 浏览器可以渲染<br />
<body>
    <button id="submit">更改Body的背景眼色</button>
</body>
<script>
    console.log(submit);
</script>
</html>

1)getElementById:通过元素的id获取元素

//DOM元素对象
document.getElementById("box");

【document】:
document 是上下文,限制范围的意思:在哪个范围下的 id名字是box的这个元素,不过这个上下文只能是 document
【id名字唯一性】:
id名字是唯一的,一个document文档中不能同时出现多个相同的id名字,如果设置了多个相同的id,只能获取到第一个。

[兼容性注意]:不要让name 和id的名字一样。因为在ie6-ie7 的时候,如果设置了name属性,通过id也可以获取到

<body>
   <input type="text" name="text">
</body>
</html>
<script>
  console.log(document.getElementById("text"));
  //  在ie6或者ie7的时候可以获取到
</script>

2)[context].getElementsByTagName:HTMLCollection 元素集合【类数组集合】

在特定的上下文中,通过标签名,获取一组元素。

  • 得到的是一个集合,如果想要操作其中的某一项,可以基于索引获取。
var omain=document.getElementById("main");
var olis=omain.getElementsByTagName("li");
// 想要获取到第二个li:olis[1]

3) [context].getElementsByCalssName:通过类名获取元素集合【类数组集合】

  • 此方法在ie6—ie8下不兼容

4)document.getElementsByName:通过name名字获取一组 【节点集合 类数组】

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

    5)[context].querySelector(“选择器”)

    通过选择器获取指定的元素,即使匹配的有多个,也只会对第一个起作用,获取到的是一个对象(给咱们平时写样式时候写选择器是一样的)
  <div class="main">
        <div class="box1"></div>
    </div>

    document.querySlector(".main>div")

6) [context】.querySelectorAll(“选择器”) 【节点集合 类数组】

通过指定的选择器获取一组节点集合

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

7)document.head

  获取Head元素对象

8) document.body

获取body元素对象

9) document.documentElement

获取html元素对象

【需求:】获取一屏幕的宽度或者高度,兼容所有的浏览器

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

1.2 【练习题】

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>

    </style>

</head>
<body>

   <div class="box1">
       <input type="text" name="he1">
   </div>
   <input class="box1" name="he1">
</body>
</html>
<script>
 function getElementsByName(value){
     var allTag=document.getElementsByTagName("*");
     var names=[];
     for(var i=0;i<allTag.length;i++){
          var item=allTag[i];
          if(item.name==value){
             names.push(item);
          }
     }
     return names;
 }
 var ary=getElementsByName("he1")
</script>

2.【修改DOM元素的样式】

1.元素.style.xxx 修改(获取)当前元素的行内样式

操作的都是行内样式,哪怕把样式写在样式表中 只要没有写在行内上,也获取不到

2.元素.className

存储/操作元素的样式类名,基于样式类的管理给予其不同的样式

<!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>
        .active{
            color:red;
            background: pink;
        }
    </style>
</head>
<body>
     <div class="box">
         <h2 class="title"></h2>
        <ul class="item" id="itembox">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
     </div>
    <script>
        var itembox=document.getElementById("itembox"),
            lilist=itembox.getElementsByTagName("li");     
        // console.dir(itembox); =>是一个DOM元素对象
        // console.dir(lilist);=>是一个元素集合

        // ======》设置样式
        /* 方式1 */
        // itembox.style.color='Red';
        // itembox.style.backgroundColor='pink';
        //简写
        //itembox.style.cssText=`color:red; background: pink;`;

        //或者样式类
        //itembox.className='active';//这样操作会把之前的样式类名覆盖
        //itembox.className+=' active';//这样也可以 加空格区分

        itembox.classList.add('active');//向指定样式集合中新增一个样式 兼容差
    </script>
</body>
</html>

3.【给DOM元素设置内容innerHTML/innerText/value】

  • innerHTML:存储当前元素的所有内容,包含标签
  • innerText:存储当前元素的文本内容
  • value: 操作表单元素

4【节点】

一个文档中包含的所有内容都是节点node



元素节点 文本节点 注释节点 文档节点
nodeType 1 3 8 9
nodeName 大写的标签名 “#text” “#comment” “#document”
nodeValue null 文本内容 注释的内容 null

1)元素节点 [“HTML标签”]

  • nodeType:1
  • nodeName:”大写的标签名”
  • nodeValue:null ```
<a name="lFZyH"></a>
### 2)文本节点 [文本内容/空格/换行]

- nodeType:3
- nodeName:"#text"
- nodeValue:文本内容
- 在标准浏览器中,换行和空格也属于文本节点

百度

```
var res=a1.childNodes[0];
console.log(res.nodeType);//3
console.log(res.nodeValue);//"百度";
console.log(res.nodeName);//"#text";

3)注释节点 “注释的内容”

  • nodeType:8
  • nodeName:”#comment”
  • nodeValue:注释的内容
    <a href="http://www.baidu.com" id="a1">
      <!--a标签 -->
      百度
    </a>
    
a1.childNodes; //NodeList(3) [text, comment, text]
a1.childNodes[1].nodeName;//"#comment"
a1.childNodes[1].nodeType;//8
a1.childNodes[1].nodeValue;//"a标签 "

4)文档节点 “document”

  • nodeType:9
  • nodeName:”#document”
  • nodeValue:null

    document.nodeType;
    document.nodeName
    document.nodeValue;
    

    5)属性节点

  • nodeType:2

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

    5【节点的关系关系属性】

    描述和获取节点之间关系的属性 已知一个节点 我们基于这些属性可以获取到任何一个跟其相关的节点

1)childNodes 集合 [NodeList]

获取当前节点所有的子节点{包含各种类型}
获取的是节点集合 空格换行是文本节点

兼容问题 在IE6-8 因为在这浏览器中,不会把空格和换行当做文本节点 不认为这是个节点

<ul id="main">
       <!-- 我是注释 -->
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
</ul>

<script>
console.log(main.childNodes);
// NodeList(11) [text, comment, text, li, text, li, text, li, text, li, text]
</script>

2) children

获取当前元素所有的元素子节点,获取的是一个元素集合

但是在ie6—ie8下不兼容 会把注释节点当成元素节点 [HTMLCollection]

console.log(main.children);

HTMLCollection(4) [li, li, li, li]

3)parentNode

获取当前节点唯一的父亲节点

4) previousSibling

获取上一个哥哥节点 {只获取一个,紧挨着的这一个,而且不一定是元素节点}

main.previousSibling
//#text

5) previousElementSibling

获取其元素哥哥节点 在ie 678 不兼容
ie6-ie8 不兼容

   <span>1</span>
   <ul id="main">
       <!-- 我是注释 -->
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
   </ul>
 <script>
 console.log(main.previousElementSibling);
 //<span>1</span>

 <script>

6)nextSibling

获取当前节点的下一个兄弟节点

   <span id="span1">1</span>
   <ul id="main">
       <!-- 我是注释 -->
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
   </ul>
   <span>2</span>

 // console.log( span.nextSibling)

7) nextElementSibling

获取当前节点的下一个元素兄弟节点
ie6-ie8 不兼容

8) firstChild

获取其所有子节点的第一个{大儿子}

9)firstElementChild

获取当前节点的第一个元素子节点
ie6-ie8 不兼容

10)lastChild

获取当前节点的最后一个子节点{小儿子}

11)lastElementChild

获取当前节点的最后一个元素子节点{小儿子}
ie6-ie8 不兼容

6【dom 的增删改】

1)createElement:动态创建一个元素节点【元素标签】

var link=document.createElement('a');
link.href="http://www.baidu.com"; //增加href属性

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

 var text=document.createTextNode('我是文本的内容');

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

+容器.appendChild(元素对象) 把元素对象放置容器的末尾
【context】.appendChild([元素]);

var odiv=documment.createElement("div");

document.body.appendChild(odiv);

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

insertBefore 把A{新增的}放到B{现有的}的前面 (B.parentNode).insertBefore(A,B)
把新元素添加到原有元素的前面
【context】.insertBefore(newEle,oldEle);

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

  • 【ele】.cloneNode(false/true);浅克隆: 只是克隆了一个节点,里面的内容还有样式都没克隆
  • 【ele】.cloneNode(true);深克隆:把节点包含的所有内容进行克隆

    6)removeChild:移除某个节点

    【context】.removeChild(ele);

    7)set/get/removeAttribute

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

  • setAttribute

  • getAttribute
  • removeAttribute
<div id="box"></div>
//=======>  setAttribute  设置
box.setAttribute("index",1);
box.getAttribute("index");
box.removeAttribute("index");
//========> 基于键值对操作
// 设置
box["aa"]=22;
// 获取
box["aa"]
//移除
delete box[aa];

基于键值对方式 增删改:修改当前对象的堆内存空间完成的(在堆内存空间可以看到)
基于Attribute dom方法增删改,是修改html结构来完成的(此种方法设置的在结构上可以看到)
以上两种方式不能混用

7.【练习题】

1) 自己手动封装一个获取节点下面的所有子元素,要求考虑兼容性。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>

    </style>

</head>
<body>
   <span id="span1">1</span>
   <ul id="main">
       <!-- 我是注释 -->
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
   </ul>
   <span>2</span>
</body>
</html>
<script>
 function children(element){
     var nodeLists=element.childNodes;
     var result=[]
      for (var i = 0; i < nodelist.length; i++) {
             var itemNode=nodelist[i];
             if(itemNode.nodeType===1){
                 result.push(itemNode);
              }
      }
     return result;
 }
 console.log(children(main));
</script>

2) 自己手动封装一个perviousElementSibling,要兼容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>

    </style>

</head>
<body>
   <span id="span1">1</span>
   <ul id="main">
       <!-- 我是注释 -->
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
       <li>选择珠峰的,都是明智的!</li>
   </ul>
   <span id="span2">2</span>
</body>
</html>
<script>
 function previousElmentSibling(ele){
     var pre=ele.previousSibling;
     while(pre&&pre.nodeType!==1){
         pre=pre.previousSibling;
     }
     return pre;
 }

 previousElmentSibling(span2)
</script>

3.获取当前节点的所有元素哥哥节点 兼容所有浏览器

   JQ中的prevAll这个方法 就是干这个的

方式1

function prevAll(node){
            var result=[];
            // 获取父节点
            var parent=node.parentNode;
            //获取子节点 自己和他所有子节点
            var nodelist=parent.childNodes;
            // 循环所有节点 元素类型是我们想要的 并且找到当前节点后就不在循环了
            for(var i=0;i<nodelist.length;i++){
                var item=nodelist[i];
                if(item===node){
                    // 找到的是自己
                    break;
                }
                // 找的不是自己 我们把元素节点存储起来
                if(item.nodeType===1){
                    result.push(item);
                }
            }
            return result;
 }

方式2

 function prevAll2(node){
            var prev=node.previousSibling;
            var result=[];
            while(prev!== null){
                if(prev.nodeType===1){
                    result.unshift(prev);
                }
                prev=prev.previousSibling;
            }
            return result;
}

4获取所有的弟弟节点

方式1

  function nextAll(node){
            var nodelist=node.parentNode.childNodes;
            var result=[];
            //倒着从最后一项开始循环
            for(var i=nodelist.length-1;i>=0;i--){
                var item=nodelist[i];
                if(item===node){
                    // 找到的是自己
                    break;
                }
                // 找的不是自己 我们把元素节点存储起来
                if(item.nodeType===1){
                    result.unshift(item);
                }
            }
            return result;
}

方式2

 function nextAll2(node){
            var result=[];
            var next=node.nextSibling;
            while(next!==null){
                if(next.nodeType===1){
                    result.push(next);
                }
                next=next.nextSibling;
            }
            return result;
}

5.获取所有的兄弟节点

方式1

function silbings(node){
        //所有的儿子中 一定包含了我和我的兄弟们
        var nodelist=node.parentNode.childNodes;
        var result=[];
        //依次遍历每一项节点 除了非元素和我本身除外 其余的存储起来
        for (var i = 0; i < nodelist.length; i++) {
            var item=nodelist[i];
            if(item.nodeType!==1||item===node){
                continue;
            }
            result.push(item);
        }
        return result;
}

方式2

 function silbings2(node){
        // 分别调用两个方法所有的哥哥和所有弟弟 就是所有的兄弟
        return prevAll2(node).concat( nextAll2(node));   
  }

6.获取当前节点的索引 他在所有兄弟中的排行

function index(node){
        //他有几个哥哥 那么它的索引就是几
        return prevAll2(node).length;
 }