JavaScript高级程序设计读书笔记11

第11章 DOM扩展

  • Selectors API和HTML5

选择符API

  • Selectors API致力于让浏览器原生支持CSS查询

querySelector()方法

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //取得body元素
    var body=document.querySelector("body");

    //取得ID为mydiv的元素
    var myDiv=document.querySelector("#myDiv");

    //取得类为“Selected”的第一个元素
    var selected = document.querySelector(".selected");

    //取得类为button的第一个图像元素
    var img=document.querySelector("img.button");
  • 通过Document类型调用querySelector方法,会在文档元素的范围内查找匹配的元素

  • 通过Element类型调用的querySelector方法,会在该元素后代元素的范围内查找匹配的元素

querySelectorAll()方法

  • querySelectorAll():返回一个NodeList实例
  • 延伸:querySelectorAll()与getElementBy系列的区别

    1.query选择符选出的元素及元素数组是静态的,getElement方法选出的元素是动态的。
    2.querySelectorAll 方法接收的参数是一个 CSS 选择符。而 getElementsBy 系列接收的参数只能是单一的className、tagName 和 name。
    3.getElementBy系列比querySelectorAll()性能好很多
    4.如果只要一次查找就可得到元素时,首选getElementBy系列,如果需要经过多级查找,才能得到元素时,首选querySelector。

matchsSelector()方法

  • 如果调用元素与该选择符匹配,返回true,否则,false

元素遍历

  • 问题:IE与其他浏览器在返回子节点时会因文本节点是否返回而存在差异,IE不返回,其他版本返回。
  • 解决方式:为DOM元素添加以下属性,不必担心空白的文本节点
  • childElementCount:返回子元素的个数。(不包括文本节点和注释)
  • firstElementChild:指向第一个子元素。firstChild的元素版。
  • lastElementChild:指向最后一个子元素。lastChild的元素版。
  • previousElementSilbing:指向前一个同辈元素。previousSibling的元素版。
  • nextElementSibling:指向后一个同辈元素。nextSibling的元素版。

HTML5

与类相关的扩充

getElementsByClassName()

  • getElementsByClassName():接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的NodeList。

    1
    2
    3
    4
    5
    //取得类中包含“username”和“current”的元素,类名的先后顺序不重要。
    var allCurrentUsernames = document.getElementsByClassName("current username");

    //取得ID为“myDiv”的元素中带有类名“selected”的所有元素:
    var selected = document.getElementById("myDiv").getElementsByClassName("selected");
  • 调用这个方法时,只有位于调用元素子树中的元素才会返回。

classList属性

  • 问题:在操作类名时,需要通过className属性添加、删除和替换类名、因为className中是一个字符串,所以即使只修改字符串一部分,也必须每次都设置整个字符串的值,如删除其中一个类或者添加一个类,操作都十分麻烦。
    <div class="bd user disabled">...</div>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //删除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(" ");
  • 解决方式:为所有元素添加classList属性
    div.classList.remove("user");

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

焦点管理

  • document.activeElement:始终都会引用DOM中当前获得了焦点的元素。
  • document.hasFocus():用于确定文档是否获得了焦点。
  • 以上的属性和方法最重要的用途就是提高web应用的无障碍性。无障碍web应用的一个主要标志就是恰当的焦点管理。

HTMLDocument的变化

  • readyState属性:通过它来实现一个指示文档已经加载完成的指示器
  • 可能的取值

    loading:正在加载文档
    complete:已经加载完文档

  • compatMode属性:区分渲染页面的模式是标准的还是混杂的
  • 可能的取值

    CSS1Compat:标准
    BackCompat:混杂

  • head属性:var head = document.head || document.getElementsByTagName("head")[0];

字符集属性

  • charset属性:表示文档中实际使用的字符集。
  • defaultCharset:表示根据默认浏览器及操作系统的设置

自定义数据属性

  • HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。
  • <div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
  • 可以通过元素的dataset属性来访问自定义属性的值。dataset属性的值是DOMStringMap的一个实例,也就是一个名值对的映射。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var div = document.getElementById("myDiv");
    //取得自定义属性的值
    var appId = div.dataset.appId;
    var myname = div.dataset.myname;
    //设置值
    div.dataset.appId = 23456;
    div.dataset.myname = "Nicholas";
    if(div.dataset.myname){
    console.log("Hello, "+ div.dataset.myname);
    }

插入标记

innerHTML属性

  • 读模式:返回调用元素的所有子节点的HTML标记。(包括元素、注释、文本节点)
  • 写模式:根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
  • 为innerHTML设置HTML字符串后,浏览器会将这个字符串解析为相应的DOM树。因此设置了innerHTML后,再从中读取HTML字符串,会得到与设置时不一样的结果。原因在于返回的字符串是根据原始HTML字符串创建的DOM数经过序列化之后的结果。

outerHTML

  • 读模式:返回调用它的元素及所有子节点的HTML标签
  • 写模式:会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素。
  • div.outerHTML = "<p>this is paragraph</p>";新创建的< p>元素会取代DOM树中的div元素。

insertAdjacentHTML()

  • insertAdjacentHTML():插入标记
  • 接收两个参数,插入位置和要插入的HTML文本。
  • beforebegin 在当前元素之前插入一个紧邻的同辈元素
  • afterbegin 在当前元素之下插入一个新的子元素或者在第一个子元素之前再插入新的子元素
  • beforeend 在当前元素之下插入一个新的子元素或者在最后一个子元素之后再插入新的子元素
  • afterend 在当前元素之后插入一个紧邻的同辈元素。

内存与性能问题

  • 在删除带有时间处理程序或者引用了其他JavaScript对象子树时,元素与事件处理程序之间的绑定关系在内存中并没有一并删除。在使用innerHTML、outerHTML和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript对象属性。
  • 因此,在使用innerHTML、outerHTML和insertAdjacentHTML()之前,最好先手工删除要被替换的元素的所有事件处理程序和js对象属性。
  • 使用innerHTML效率明显高,这是由于使用属性时创建的解释器是在浏览器级别的代码基础上运行的。

scrollIntoview()

  • 如果给这个方法传入true作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。
  • 如果传入false作为参数,调用元素会尽可能全部出现在视口中,(可能的话,调用元素的底部会与视口底部平齐),但是顶部不一定平齐。

专有扩展

文档模式

  • 页面的文档模式决定了可以使用什么功能

children属性

  • 是HTMLCollection的实例,只包含元素中同样还是元素的子节点

contains()

  • 调用这个方法的是祖先节点。这个方法接收一个参数,即要检测的后代节点。如果是后代节点则返回true。
  • DOM Level 3 compareDocumentPosition()也能确定节点间的关系。返回一个表示该关系的位掩码。
掩码 节点关系
1 无关
2 居前
4 局后
8 包含(给定的节点是参考节点的祖先)
16 被包含(给定节点是参考节点的后代)

插入文本

  • innerText属性会过滤html标签
  • outerText属性将作用范围扩大到了包含调用它的节点之外。
  • scrollIntoViewIfNeeded(alignCenter) 如果不可见才滚动,参数设置true表示尽量将元素显示在视口中部
  • scrollByLines() 将元素的内容滚动指定行高
  • scrollByPages() 将元素的内容滚动指定页面高度