DOM操作

作者: yuhuan121 | 来源:发表于2017-07-20 23:03 被阅读0次

    文档对象模型 DOM


    DOM 是 JavaScript 操作⽹页的接口,全称为“文档对象模型”(Document Object Model)。它的作用是将⽹页转为一个 JavaScript 对象,从而可以⽤脚本进行各种操作 (⽐如增删内容)。
    DOM 的最小组成单位叫做节点(node)。⽂档的树形结构(DOM树),就是由各种不同类型的节点组成。

    DOM树

    节点的类型有七种


    浏览器提供⼀个原生的节点对象 Node ,下面这七种节点都继承了 Node ,因此具有⼀些共同的属性和⽅法。最常用的是document对象和Element对象。

    • Document :整个文档树的顶层节点
    • DocumentType : doctype 标签(⽐如 <!DOCTYPE html> )
    • Element :⽹页的各种HTML标签(比如 <body> 、 <a> 等)
    • Attribute :⽹页元素的属性(⽐如 class="right" )
    • Text :标签之间或标签包含的⽂本
    • Comment :注释
    • DocumentFragment :⽂档的⽚段

    document 对象


    每个载入浏览器的HTML文档都会成为document对象。document对象表示整个HTML页面,是window对象的一个属性。

    document对象常用属性

    document.doctype   //获取HTML文档的doctype声明,例如<!DOCTYPE html>,没有则返回null
    document.title  //返回当前文档的标题,该属性是可写的
    document.characterSet //返回渲染当前文档的字符集,例如"UTF-8"
    document.head //获取文档中被head节点包裹的内容
    document.body //获取文档中被body节点包裹的内容
    document.images //获取文档中所有图片
    
    document.readyState // 返回当前文档的状态,共有三种可能的值
    //1. loading:加载HTML代码阶段,尚未完成解析
    //2. interactive:加载外部资源阶段
    //3. complete:全部加载完成
    
    document.compatMode 属性返回浏览器处理文档的模式,共有两种可能的值
    //1. BackCompat:向后兼容模式,也就是没有添加DOCTYPE
    //2. CSS1Compat:严格模式,添加了DOCTYPE
    
    document.activeElement //返回当前文档中获得焦点的那个元素
    //用户通常可以使用tab键移动焦点,使用空格键激活焦点
    
    document.location //返回一个只读对象,提供了当前文档的URL信息
    document.location === location //true
    document.location === window.location //true
    // 假定当前网址为http://user:passwd@www.example.com:4097/path/a.html?x=111#part1
    document.location.href // "http://user:passwd@www.example.com:4097/path/a.html?x=111#part1"
    document.location.protocol // "http:"
    document.location.host // "www.example.com:4097"
    document.location.hostname // "www.example.com"
    document.location.port // "4097"
    document.location.pathname // "/path/a.html"
    document.location.search // "?x=111"
    document.location.hash // "#part1"
    document.location.user // "user"
    document.location.password // "passed"
    document.location.assign('http://www.google.com') //跳转到另一个网址
    document.location.reload(true) // 优先从服务器重新加载
    document.location.reload(false) // 优先从本地缓存重新加载(默认值)
    document.location.assign('http://www.google.com') // 跳转到另一个网址,但当前文档不保留在history对象中,即无法用后退按钮,回到当前文档
    document.location.toString() // 将location对象转为字符串,等价于document.location.href
    //虽然location属性返回的对象是只读的,但是可以将指定的URL赋值给这个属性!网页就会自动跳转到指定网址。
    document.location = 'http://www.example.com';// 即跳转至网页http://www.example.com
    
    document.cookie //获取该文档的cookie信息,cookie是存储在客户端的文本
    
    document.getElementById('XXX').innerText //返回元素内包含的文本内容,可写属性,在多层次的时候会按照元素由浅到深的顺序拼接其内容。
    <div>
        <p>
            123
            <span>456</span>
        </p>
    </div>
    外层div的innerText返回内容是 "123456"
    
    document.getElementById('XXX').innerHTML //和inerText类似,但不是返回元素的文本内容,而是返回元素的HTML结构
    <div>
        <p>
            123
            <span>456</span>
        </p>
    </div>
    外层div的innerHTML返回内容是<p>123<span>456</span></p>
    
    document.open(); //新建一个文档,供write方法写入内容。它实际上等于清除当前文档,重新写入内容
    document.write("hello"); //向当前文档写入内容
    document.write("world"); 
    document.close(); //用于关闭open方法所新建的文档。一旦关闭,write方法就无法写入内容了
    注意:
    1.如果页面已经渲染完成再调用write方法,它会先调用open方法,擦除当前文档所有内容,然后再写入。
    2.如果在页面渲染过程中调用write方法,并不会调用open方法。
    

    Element对象


    除了document对象,在DOM中最常用的就是Element对象了,Element对象表示HTML元素,提供了对元素标签名、子节点以及特性的访问。
    Element 对象可以拥有类型为元素节点、文本节点、注释节点的子节点,DOM提供了一系列的方法可以进行元素的增、删、改、查操作。

    Element对象属性

    nodeName:元素标签名,还有个类似的tagName
    nodeType:元素类型
    className:类名
    id:元素id
    children:子元素列表(HTMLCollection)
    childNodes:子元素列表(NodeList)
    firstChild:第一个子元素
    lastChild:最后一个子元素
    nextSibling:下一个兄弟元素
    previousSibling:上一个兄弟元素
    parentNode、parentElement:父元素
    

    用法举例:

    document.getElementById("MathJax_Message").nodeName  //"DIV"
    

    查询元素 (querySelector()最佳)

    getElementById()
    返回匹配指定ID属性的元素节点。

    var elem = document.getElementById("test");
    

    getElementsByClassName()
    返回一个类数组的对象,包括了所有class名字符合指定条件的元素

    var elements = document.getElementsByClassName(names);
    document.getElementsByClassName('red test');
    

    getElementsByClassName方法的参数,可以是多个空格分隔的class名字,返回同时具有这些节点的元素。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。

    getElementsByTagName()
    getElementsByTagName方法返回所有指定标签的元素(搜索范围包括本身)。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。

    var paras = document.getElementsByTagName("p");
    

    querySelector()
    querySelector方法返回匹配指定的CSS选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。
    即通过querySelector()使用css选择器的方法去操作dom元素,需要注意兼容性,支持IE9及以上,对IE8部分支持

    var el1 = document.querySelector(".myclass");
    var el2 = document.querySelector('#myParent > [ng-click]');
    

    注意:querySelector方法无法选中CSS伪元素。

    querySelectorAll()
    querySelectorAll方法返回匹配指定的CSS选择器的所有节点,返回的是NodeList类型的对象。NodeList对象不是动态集合,所以元素节点的变化无法实时反映在返回结果中。

    elementList = document.querySelectorAll(selectors);
    

    querySelectorAll方法的参数,可以是逗号分隔的多个CSS选择器,返回所有匹配其中一个选择器的元素。

    var matches = document.querySelectorAll("div.note, div.alert");
    

    上面代码返回class属性是note或alert的div元素。

    创建元素

    createElement(标签名)
    createElement方法用来生成HTML元素节点。

    var newDiv = document.createElement("div");
    

    createElement方法的参数为元素的标签名,即元素节点的tagName属性。
    如果传入大写的标签名,会被转为小写。如果参数带有尖括号(即<和>)或者是null,会报错。

    createTextNode()
    createTextNode方法用来生成文本节点,参数为所要生成的文本节点的内容。

    var newDiv = document.createElement("div");
    var newContent = document.createTextNode("Hello");
    

    上面代码新建一个div节点和一个文本节点

    createDocumentFragment()
    createDocumentFragment方法生成一个DocumentFragment对象。

    var docFragment = document.createDocumentFragment();
    

    DocumentFragment对象是一个存在于内存的DOM片段,但是不属于当前文档,常常用来生成较复杂的DOM结构,然后插入当前文档。这样做的好处在于,因为DocumentFragment不属于当前文档,对它的任何改动,都不会引发网页的重新渲染,比直接修改当前文档的DOM有更好的性能表现。

    修改元素&删除元素&clone元素

    appendChild()
    接受一个节点对象作为参数,将其作为最后一个子节点,插入当前节点。

    var newDiv = document.createElement("div");
    var newContent = document.createTextNode("Hello");
    newDiv.appendChild(newContent);
    

    上面代码将新建的文本节点插入到新建的div节点的尾部。

    var p = document.createElement('p');
    document.body.appendChild(p);
    

    上面代码新建一个<p>节点,将其插入document.body的尾部。

    如果appendChild方法的参数是DocumentFragment节点,那么插入的是DocumentFragment的所有子节点,而不是DocumentFragment节点本身。返回值是一个空的DocumentFragment节点。

    insertBefore()
    insertBefore方法用于将某个节点插入父节点内部的指定位置。

    var insertedNode = parentNode.insertBefore(newNode, referenceNode);
    

    insertBefore方法接受两个参数,第一个参数是所要插入的节点newNode,第二个参数是父节点parentNode内部的一个子节点referenceNode。newNode将插在referenceNode这个子节点的前面。返回值是插入的新节点newNode。

    var newDiv = document.createElement("div");
    var newContent = document.createTextNode("Hello");
    newDiv.insertBefore(newContent, newDiv.firstChild);
    

    newContent将插在newDiv.firstChild的前面

    如果insertBefore方法的第二个参数为null,则新节点将插在当前节点内部的最后位置,即变成最后一个子节点。

    var newDiv = document.createElement("div");
    var newContent = document.createTextNode("Hello");
    newDiv.insertBefore(newContent, null);
    

    由于不存在insertAfter方法,如果新节点要插在父节点的某个子节点后面,可以用insertBefore方法结合nextSibling属性模拟。

    parent.insertBefore(s1, s2.nextSibling);
    

    replaceChild()替换指定元素
    replaceChild()接受两个参数:要插入的元素和要替换的元素,返回值是替换走的那个节点oldElement。

    newDiv.replaceChild(newElement, oldElement);
    

    removeChild()移除子节点
    接受一个子节点作为参数,用于从当前节点移除该子节点。返回值是移除的子节点。

    parentNode.removeChild(childNode);
    

    Node.hasChildNodes()判断是否有子节点
    hasChildNodes方法返回一个布尔值,表示当前节点是否有子节点。

    var foo = document.getElementById('foo');
    
    if (foo.hasChildNodes()) {
      foo.removeChild(foo.childNodes[0]);
    }
    

    上面代码表示,如果foo节点有子节点,就移除第一个子节点。

    cloneNode()克隆一个节点
    它接受一个布尔值作为参数,表示是否同时克隆子节点,false的时候只复制元素本身。它的返回值是一个克隆出来的新节点。

    var cloneUL = document.querySelector('ul').cloneNode(true);
    

    该方法有一些使用注意点。

    1. 克隆一个节点,会拷贝该节点的所有属性,但是会丧失addEventListener方法和on-属性(即node.onclick = fn),添加在这个节点上的事件回调函数。
    2. 该方法返回的节点不在文档之中,即没有任何父节点,必须使用诸如Node.appendChild这样的方法添加到文档之中。
    3. 克隆一个节点之后,DOM 有可能出现两个有相同id属性(即id="xxx")的网页元素,这时应该修改其中一个元素的id属性。如果原节点有name属性,可能也需要修改。

    contains()判断是否包含和这个节点

    document.body.contains(node)
    返回一个布尔值,表示参数节点是否满足以下三个条件之一。

    1. 参数节点为当前节点。
    2. 参数节点为当前节点的子节点。
    3. 参数节点为当前节点的后代节点。
    document.body.contains(node)
    

    上面代码检查参数节点node,是否包含在当前文档之中。

    HTMLCollection 和 NodeList

    节点都是单个对象,有时需要一种数据结构,能够容纳多个节点。DOM 提供两种节点集合,用于容纳多个节点:NodeList和HTMLCollection。

    NodeList 对象代表一个有顺序的节点列表,HTMLCollection 是一个接口,表示 HTML 元素的集合,它提供了可以遍历列表的方法和属性。都是类数组对象, NodeList 有 forEach 方法,而 HTMLCollection 没有。

    以下方法获取HTMLCollection对象实例

    document.images //所有img元素
    document.links //所有带href属性的a元素和area元素
    document.forms //所有form元素
    document.scripts //所有script元素
    document.body.children
    document.getElementsByClassName("class1")
    

    以下方法获取NodeList对象实例

    Node.childNodes
    document.querySelectorAll()
    document.getElementsByTagName()
    document.getElementsByName("name1")
    
    document.body.childNodes instanceof NodeList // true
    

    NodeList实例是一个类数组对象,具有length属性和forEach方法(也可以用for遍历),可以使用方括号运算符取出成员。但不能使用pop或push之类数组特有的方法。

    var children = document.body.childNodes;
    Array.isArray(children) // false
    
    children.length // 34
    children.forEach(console.log)
    document.body.childNodes[0] //返回第一个成员
    

    如果NodeList实例要使用数组方法,可以使用Array.prototype.slice.call()将其转为真正的数组。

    var children = document.body.childNodes;
    var nodeArr = Array.prototype.slice.call(children);
    

    注意:NodeList 实例可能是动态集合,也可能是静态集合。所谓动态集合就是一个活的集合,DOM 删除或新增一个相关节点,都会立刻反映在 NodeList 实例。目前,只有Node.childNodes返回的是一个动态集合,其他的 NodeList 都是静态集合。

    var children = document.body.childNodes;
    children.length // 18
    document.body.appendChild(document.createElement('p'));
    children.length // 19
    

    上面代码中,文档增加一个子节点,NodeList 实例children的length属性就增加了1。

    NodeList.prototype.length

    length属性返回NodeList 实例包含的节点数量。

    document.getElementsByTagName('xxx').length
    

    NodeList.prototype.forEach()

    forEach方法用于遍历 NodeList 的所有成员。它接受一个回调函数作为参数,每一轮遍历就执行一次这个回调函数,用法与数组实例的forEach方法完全一致。

    var children = document.body.childNodes;
    children.forEach(function(item,i,list){})
    

    回调函数的三个参数依次是当前元素、当前元素索引值、整个NodeList 实例

    NodeList.prototype.keys(),NodeList.prototype.values(),NodeList.prototype.entries()

    keys()返回键名的遍历器,values()返回键值的遍历器,entries()返回的遍历器同时包含键名和键值的信息。都可以通过for...of循环遍历获取每一个成员的信息。

    var children = document.body.childNodes;
    
    for (var key of children.keys()) {
      console.log(key);
    }
    // 0
    // 1
    // 2
    // ...
    
    for (var value of children.values()) {
      console.log(value);
    }
    // #text
    // <script>
    // ...
    
    for (var entry of children.entries()) {
      console.log(entry);
    }
    // Array [ 0, #text ]
    // Array [ 1, <script> ]
    // ...
    

    属性操作

    getAttribute()获取元素的attribute值(一个标签的属性名和属性值可以自己定义)

    var node = document.querySelector('p')
    node.getAttribute('id');
    

    setAttribute(属性名,属性值) 设置元素属性

    var node = document.getElementById("div1");
    node.setAttribute("my_attrib", "newVal");
    

    romoveAttribute() 删除元素属性

    node.removeAttribute('id');
    

    常见使用方式

    样式的改变建议使用 class 的新增删除来实现

    Element.classList方法: 操作元素的class

    var nodeBox = document.querySelector('.box')
    console.log( nodeBox.classList )
    nodeBox.classList.add('active')   //新增 class
    nodeBox.classList.remove('active')  //删除 class
    nodeBox.classList.toggle('active')   //新增/删除切换(即如果类存在,则删除它并返回false,如果不存在,则添加它并返回true。)
    node.classList.contains('active')   // 判断是否存在指定的class
    Element.classList.item ( Number ) //按集合中的索引返回class值
    

    页面宽高

    网页可见区域宽: document.body.clientWidth;
    网页可见区域高: document.body.clientHeight;
    网页可见区域宽: document.body.offsetWidth (包括边线的宽);
    网页可见区域高: document.body.offsetHeight (包括边线的宽);


    image
    image

    网页正文全文宽: document.body.scrollWidth;
    网页正文全文高: document.body.scrollHeight;
    网页被卷去的高: document.body.scrollTop;
    网页被卷去的左: document.body.scrollLeft;
    网页正文部分上: window.screenTop;
    网页正文部分左: window.screenLeft;
    屏幕分辨率的高: window.screen.height;
    屏幕分辨率的宽: window.screen.width;
    屏幕可用工作区高度: window.screen.availHeight;
    屏幕可用工作区宽度:window.screen.availWidth;

    Element.scrollHeight: 只读属性,是一个元素内容高度的度量
    Element.scrollTop:获取或设置一个元素的内容垂直滚动的像素数
    scrollWidth:获取对象的滚动宽度
    offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度
    offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置
    event.clientX 相对文档的水平座标
    event.clientY 相对文档的垂直座标
    event.offsetX 相对容器的水平坐标
    event.offsetY 相对容器的垂直坐标
    event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量

    相关文章

      网友评论

          本文标题:DOM操作

          本文链接:https://www.haomeiwen.com/subject/emtzhxtx.html