DOM扩展

选择符API

querySelector()方法

  • querySelector()方法接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null

    //取得body元素
    var body=document.querySelector("body");
    //取得ID为"myDiv"的元素
    var myDiv=document.querySelector("#myDiv");
    //取得类为"selected"的第一个元素
    var selected=document.querySelector(".selector");
    //取得类为"button"的第一个元素
    var img=document.body.querySelector("img.button")
  • 如果传入了不被支持的选择符,querySelector()会抛出错误

querySelectorAll()方法

  • querySelectorAll()方法接收的参数与querySelector()方法一样,都是一个CSS选择符,但返回的是所有匹配元素而不是一个元素。这个方法返回的是一个NodeList的实例
  • 底层实现类似于一组元素的快照,而非不断对文档进行搜索的动态查询。

    //取得某<div>中的所有<em>元素
    var em =document.getElementById("myDiv").querySelectorAll("em")
    //取得类为"selected"的所有元素
    var selected=document.querySelectorAll(".selected");
    //取得所有<p>元素中的所有<strong>元素
    var strongs=document.querySelectorAll("p strong")
    
    //要取得返回的NodeList中的每一个元素,可以使用item()方法,也可以使用方括号语法
    var i,len,strong;
    for(i=0,len=strong.length;i<len;i++){
      strong=strong[i];//或者strong.item(i)
      strong.className="important"
    }

matchesSelector()方法

  • 这个方法接收一个参数,即CSS选择符,如果调用元素与该选择符匹配,返回true,否则返回false

    function matchesSelector(element, selector){
      if (element.matchesSelector){
        return element.matchesSelector(selector);
      } else if (element.msMatchesSelector){
        return element.msMatchesSelector(selector);
      } else if (element.mozMatchesSelector){
        return element.mozMatchesSelector(selector);
      } else if (element.webkitMatchesSelector){
        return element.webkitMatchesSelector(selector);
      } else {
        throw new Error("Not supported.");
      }
    }
    if (matchesSelector(document.body, "body.page1")){
      //执行操作
    }

元素遍历

  • DOM新增的5个属性

    • childElementCount,返回子元素的个数,不包括文本节点和注释
    • firstElementCount,指向第一个子元素,firstChild的元素版
    • lastElementCount,指向最后一个子元素,lastChild的元素版
    • previousElementSibling,指向前一个同辈元素,previousSibling的元素版
    • nextElementSibling,指向后一个同辈元素,nextSibling的元素版
    var i,
        len,
        child = element.firstChild;
    while(child != element.lastChild){
      if (child.nodeType == 1){ //检查是不是元素
        processChild(child);
      }
      child = child.nextSibling;
    }
    //使用新增的元素代码会更简洁
    var i,
        len,
        child = element.firstElementChild;
    while(child != element.lastElementChild){
      processChild(child); //已知其是元素
      child = child.nextElementSibling;
    }

HTML5

与类相关的补充

  • getElementsByClassName()方法接收一个参数,即一个包含一或多个类名的字符串,返回带有制定类的所有元素的NodeList,传入多个类名时,类名的先后顺序不重要。
  • getElementsByClassName()始终会返回与类名匹配的所有元素,在元素上调用方法就会返回后代元素中匹配的元素。
  • 操作类名时可以通过className属性添加、删除和替换类名。因为className中是一个字符串,所以即使只修改字符串的一部分,也必须每次都设置整个字符串的值

    <div class="bd user disabled">...</div>
    //删除"user"类
    //首先,取得类名字符串并拆分成数组
    var classNames = div.className.split(/\s+/);
    //找到要删的类名
    var pos = -1,
        i,
        len;
    for (i=0, len=classNames.length; i < len; i++){
      if (classNames[i] == "user"){
        pos = i;
        break;
      }
    }
    //删除类名
    classNames.splice(i,1);
    //把剩下的类名拼成字符串并重新设置
    div.className = classNames.join(" ");
  • HTML5为所有元素添加classList属性,简化上述操作

    • add(value),将给定的字符串添加到列表中,如果值已经存在,就不添加了
    • contain(value),表示列表中是否存在给定的值,如果存在则返回true,否则返回false
    • remove(value),从列表中删除给定的字符串
    • toggle(value),如果列表中已经存在给定的值,删除。如果列表中没有给定的值,添加。
    //删除"disabled"类
    div.classList.remove("disabled");
    //添加"current"类
    div.classList.add("current");
    //切换"user"类
    div.classList.toggle("user");
    //确定元素中是否包含既定的类名
    if (div.classList.contains("bd") && !div.classList.contains("disabled")){
    //执行操作
    )
    //迭代类名
    for (var i=0, len=div.classList.length; i < len; i++){
    doSomething(div.classList[i]);
    }

焦点管理

  • document.activeElement属性会引用DOM中当前获得了焦点的元素,元素获得焦点的方式有页面加载、用户输入和在代码中调用focus()方法

    var button=document.getElementById("myButton");
    button.focus();
    alert(document.activeElement===button);//true
  • 默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body元素的引用。文档加载期间,document.activeElement的值为null
  • 新增document.hasFocus()方法,用于确定文档时候获得了焦点

    var button=document.getElementById("myButton");
    button.focus();
    alert(document.hasFocus());//true

HTMLDocument的变化

  • Document的readyState属性有两个可能的值

    • loading,正在加载的文档
    • complete,已经加载完的文档
  • 使用document.readyState的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器

    if(document.readyState=="complete"){
      //执行操作
    }
  • document添加了一个名为compatMode的属性,这个属性就是为了告诉开发人员浏览器采用了哪种渲染模式。标准模式下,document.compatMode的值等于"CSS1Compat",而在混杂模式下,document.compatMode的值等于"BackCompat"

    if(document.compatMode=="CSS1Compat"){
      alert("Standards mode");
    }else {
      alert("Quirks mode");
    }
  • 作为对document.body引用文档的<body>元素的补充,HTML5新增了document.head属性,引用文档的<head>元素,可以结合使用这个属性和另一种后备方法

    var head=document.head||document.getElementByTagName("head")[0];

字符集属性

自定义数据属性

  • 可以为元素添加非标准的属性,但要添加前缀data-

    <div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
  • 可以通过元素的dataset属性类访问自定义属性的值

    //本例中使用的方法仅用于演示
    var div = document.getElementById("myDiv");
    //取得自定义属性的值
    var appId = div.dataset.appId;
    var myName = div.dataset.myname;
    //设置值
    div.dataset.appId = 23456;
    div.dataset.myname = "Michael";
    //有没有"myname"值呢?
    if (div.dataset.myname){
      alert("Hello, " + div.dataset.myname);
    }

插入标记

  • innerHTML

    • 在读模式下,innerHTML属性返回与调用元素的所有子节点对应的HMTL标记。在写模式下,innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。

      <div id="content">
        <p>This is a <strong>paragraph</strong> with a list following it.</p>
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
        </ul>
      </div>
      //上面元素innerHTML属性会返回下面的字符串
      <p>This is a <strong>paragraph</strong> with a list following it.</p>
        <ul>
        <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      </ul>
      div.innerHTML="Hello & welcome,<b>\"reader\"!</b>"
      //操作之后得到下面的HTML代码
      <div id="content">Hello &amp; welcome, <b>&quot;reader&quot;!</b></div>
    • 只要使用innerHTML从外部插入HTML,都应该首先以可靠的方式处理HTML,IE8提供了window.toStationHTML()方法,这个方法接收一个参数,即一个HTML字符串,返回一个经过无害处理后的版本,从源HTML中删除所有脚本节点和事件处理程序属性
  • outerHTML

    • 在读模式下,outerHTML返回调用它的元素及所有子节点的HTML标签。在写模式下,outerHTML会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素

      <div id="content">
        <p>This is a <strong>paragraph</strong> with a list following it.</p>
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
        </ul>
      </div>
    • 如果调用outerHTML会返回和上面相同的代码,包括<div>本身

      //设置outerHTML属性
      div.outerHTML="<p>This is a paragraph.</p>"
  • insertAdjacentHTML

    • 接收两个参数,插入位置和要插入的HTML文办,第一个参数必须是下列值之一

      • beforebegin,在当前元素之前插入一个紧邻的同辈元素
      • afterbegin,在当前元素之前插入一个新的子元素或在第一个子元素之前再插入新的子元素
      • beforeend,在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素
      • afterend,在当前元素之后插入一个紧邻的同辈元素
//作为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>");
//作为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
//作为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
//作为后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");

scrollIntoView()方法

  • scrollIntoView()可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中,如果给这个方法传入true作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐,如果传入false作为参数,调用元素会尽可能全部出现在视口中

    //让元素可见
    document.forms[0]/scrollIntoView();

专有扩展

文档模式

  • 页面的文档模式决定了可以使用什么功能。文档模式决定了可以使用哪个级别的CSS,可以在JavaScript中使用哪些API,以及如何对待文档类型

    • IE5,以混杂模式渲染页面,IE8以及更高的版本功能无法使用
    • IE7,以IE7标准模式渲染页面,IE8以及更高额版本功能无法使用
    • IE8,以IE8标准模式渲染页面,IE8的新功能可以使用,IE9新功能无法使用
    • IE9,以IE9标准模式渲染页面,IE9新功能都可以使用
  • 如果想让文档模式像IE7中一样,使用以下代码

    <meta http-qeuiv="X-UA-Compatible" content="IE=EmulateIE7">
  • 如果不考虑文档类型声明,直接使用IE7标准模式

    <meta http-equiv="X-UA-Compatible" content="IE=7">

children属性

  • 元素只包含元素子节点时,两个属性的值相同

    var childCount=element.children.length;
    var firstChild=element.children[0]

contains()方法

  • 调用contain()方法的应该是祖先节点,也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,该方法返回true,否则返回false

    alert(document.documentElement.contain(document.body))//true
  • 使用浏览器及能力检测,写出通用的contain函数

    function contains(refNode, otherNode){
      if (typeof refNode.contains == "function" &&
          (!client.engine.webkit || client.engine.webkit >= 522)){
        return refNode.contains(otherNode);
      } else if (typeof refNode.compareDocumentPosition == "function"){
        return !!(refNode.compareDocumentPosition(otherNode) & 16);
      } else {
        var node = otherNode.parentNode;
        do {
          if (node === refNode){
            return true;
          } else {
            node = node.parentNode;
          }
        } while (node !== null);
        return false;
      }
    }

插入文本

  • innerText

    • 通过这个属性可以操作元素中包含的所有文本内容,包括子文档树中的文本,在通过innerText读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来,在通过innerText写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点

      <div id="content">
        <p>This is a <strong>paragraph</strong> with a list following it.</p>
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
        </ul>
      </div>
      //对于上面的<div>元素而言,其innerText属性会返回下列字符串
      This is a paragraph with a list following it.
      Item 1
      Item 2
      Item 3
    • 设置这个属性

      div.innerText="Hello world";
      //执行完之后结果是下方代码
      <div id="content">Hello world!</div>
    • 编写代码检测属性
    function getInnerText(element){
      return (typeof element.textContent == "string") ?
        element.textContent : element.innerText;
    }
    function setInnerText(element, text){
      if (typeof element.textContent == "string"){
        element.textContent = text;
      } else {
        element.innerText = text;
      }
    }
  • outerText

    • outerText不只是替换它元素的自己诶单,而是会替换整个元素,包括子节点

滚动

  • 对HTMLElement类型拓展的几个方法

    • scrollIntoViewIfNeeded(alignCenter) :只在当前元素在视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做。如果将可选的 alignCenter 参数设置为 true ,则表示尽量将元素显示在视口中部(垂直方向)。Safari 和 Chrome 实现了这个方法。
    • scrollByLines(lineCount) :将元素的内容滚动指定的行高, lineCount 值可以是正值,也可以是负值。Safari 和 Chrome 实现了这个方法。
    • scrollByPages(pageCount) :将元素的内容滚动指定的页面高度,具体高度由元素的高度决定。Safari 和 Chrome 实现了这个方法。
    //将页面主体滚动 5 行
    document.body.scrollByLines(5);
    //在当前元素不可见的时候,让它进入浏览器的视口
    document.images[0].scrollIntoViewIfNeeded();
    //将页面主体往回滚动 1 页
    document.body.scrollByPages(-1);

神膘护体小月半
406 声望6 粉丝