一、选择符API扩展
querySelector()
该方法接受一个CSS选择符,返回与该模式匹配的第一个元素。没有匹配的元素则返回null
。在Document
类型调用该方法会在文档元素的范围内查找匹配元素,在Element
类型调用该方法会在该元素的后代范围内查找匹配元素。传入非法的选择符时会抛出错误。
1 | var div = document.querySelector("div"); |
querySelectorAll()
该方法参数与querySelector()
方法一样,但返回的是一个NodeList
实例,包含所有匹配的元素。如果没有匹配的元素,则返回一个空的NodeList
。返回的NodeList
带有属性方法,其底层实现类似于一组元素的快照,而非不断对文档进行搜索的动态查询,从而避免了使用NodeList
通常会引起的大多数性能问题。
1 | var div = document.querySelectorAll("div"); |
matchesSelector()
该方法接受一个CSS选择符,如果调用元素与该选择符匹配则返回true
,否则返回false
。
1 | var div = document.querySelector("div.aha"); |
二、元素遍历扩展
Element Traversal API为DOM元素添加了以下5个属性:
childElementCount
: 返回子元素(不包括文本节点和注释)的个数firstElementChild:
指向第一个子元素;firstChild
的Element
版lastElementChild
: 指向最后一个子元素;lastChild
的Element
版previousElementSibling
: 指向前一个同辈元素;previousSibling
的Element
版nextElementSibling
: 指向后一个同辈元素;nextSibling
的Element
版
过去,要跨浏览器遍历某元素的所有子元素,需要像下面的示例1一样去写代码,childNodes
列表中包含元素节点、文本节点、注释节点等信息,因此需要检测元素节点。而有了上面5个拓展属性之后就可使得代码更加简洁,而且循环次数更少,如示例2。
1 | // 示例1 |
三、HTML5扩展
与类相关的扩充
getElementsByClassName()
: 该方法接受一个参数,即包含一个或多个类型的字符串,返回一个NodeList
,包含所有带有指定类型的元素。
classList
属性: 在操作类名时,需要通过className
属性添加、删除和替换类名,由于className
的值是一个字符串,所以每次修改都需要替换整个字符串的值,如果元素有多个类名,仅修改其中一个类名都需要写不少代码,非常麻烦。classList
的出现解决了这些麻烦,使得操作类名更简单更安全。classList
属性是新集合类型DOMTokenList
的实例,有length
属性表示包含的元素数量,通过item()
方法或方括号语法可以取得每个元素。DOMTokenList
还有以下方法:
add(value)
: 将给定的字符串添加到列表中contains(value)
: 如果列表中存在给定的值,返回true
,否则返回false
remove(value)
: 从列表中删除给定字符串toggle(value)
: 如果列表中存在给定值,删除它,否则添加它
下面给出代码示例,示例1展示了使用className
修改类名的过程,示例2则是使用classList
的过程。
1 | // 示例1,删除"xxx"类 |
焦点管理
document.activeElement
: 引用DOM中当前获得了焦点的元素。元素获得焦点的方式有页面加载、用户输入和代码中调用focus()
方法。默认情况下,文档刚刚加载完时,document.activeElement
中保存的是document.body
元素的引用。文档加载期间,document.activeElement
的值是null
。
document.hasFocus()
: 该方法用于确定文档是否获取了焦点,便于检测用户是否正在与页面交互。
1 | var btn = document.getElementById("#btn"); |
HTMLDocument
document.readyState
: Document
的readyState
属性有两个可能值,"loading"
表示正在加载文档,"complete"
表示已经加载完文档。document.readyState
的基本用法如下:
1 | if (document.readyState == "complete") { |
document.compatMode
: 该属性用于告诉开发人员浏览器采用了哪种渲染模式,标准模式下其值为"CSS1Compat"
,混杂模式下其值为"BackCompat"
。
document.head
: 包含对<head>
元素的引用。
字符集属性
document.charset
: 表示文档中使用的字符集。基本用法如下:
1 | console.log(document.charset); |
document.defaultCharset
: 表示根据默认浏览器及操作系统的设置,当前文档的默认字符集应该是什么。
自定义数据属性
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-
,目的是为元素提供与渲染无关的信息或者语义信息。这些属性可以任意添加、随便命名,但必须以data-
开头。添加自定义属性之后在JS中可以通过元素的dataset
属性来访问。dataset
是一个键值对,每个data-name
形式的属性都会有一个对应的属性,属性名会去掉data-
前缀。
1 | // <div id="myDiv" data-name="xxx" data-phone="123" data-email="yyy"></div> |
插入标记
innerHTML
属性:在读模式下,innerHTML
属性返回与调用元素的所有子节点(包括元素、注释、文本)对应的HTML标记。在写模式下,会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
1 | <div id="myDiv"> |
1 | var div = document.getElementById("myDiv"); |
outerHTML
属性:读模式下,outerHTML
返回调用它的元素以及所有子节点的HTML标签。在写模式下会根据指定的HTML字符串创建新的DOM子树,然后用这个子树完全替换调用元素。
1 | <div id="div-1"> |
1 | var div2 = document.getElementById("div-2"); |
insertAdjacentHTML()
方法:该方法接受两个参数,要插入的位置和要插入的HTML文本。第一个参数必须是下列值之一:
"beforebegin"
: 在当前元素之前插入一个紧邻的同辈元素"afterbegin"
: 在当前元素下插入一个新的子元素,新元素放在原有的第一个子元素之前"beforeend"
: 在当前元素的最后一个子元素后面插入新的子元素"afterend"
: 在当前元素后面插入一个紧邻的同辈元素
下面是代码示例:
1 | element.insertAdjacentHTML("beforebegin", "<p>haha~</p>"); |
内存与性能问题:
假设某个元素有一个事件处理程序(或者引用了一个JS对象作为属性),在使用上述的某个属性将该元素从文档树中删除后,元素与事件处理程序(或JS对象)之间的绑定关系在内存中并没有一并删除。如果这种情况频繁出现,页面占用的内存数量就会明显增加。因此,在使用
innerHTML
、outerHTML
和insertAdjacentHTML()
时最好先手动删除要被替换元素的所有事件处理程序和JS对象属性。使用
innerHTML
属性与通过多次DOM操作先创建节点再指定它们之间的关系相比,效率要高很多。这是因为在设置innerHTML
或outerHTML
时,就会创建一个HTML解析器,这个解析器是在浏览器级别的代码(通常是C++)基础上运行,比执行JS要快得多。此外,创建和销毁这个HTML解析器也会带来性能损失,所以最好将设置innerHTML
和outerHTML
的次数控制在合理的范围之内。
scrollIntoView()方法
该方法可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。当页面发生变化时,一般会用这个方法来吸引用户的注意力。实际上,为某个元素设置焦点也会导致浏览器滚动并显示出获得焦点的元素。