JavaScript-DOM(五)
6、CSS 伪元素样式的获取
CSS 伪元素是通过 CSS 向 DOM 添加的元素,主要是通过:before
和:after
选择器生成,然后用content
属性指定伪元素的内容。
下面是一段 HTML 代码。
<div id="test">Test content</div>
CSS 添加伪元素:before
的写法如下。
#test:before {
content: 'Before ';
color: #FF0;
}
节点元素的style
对象无法读写伪元素的样式,这时就要用到window.getComputedStyle()
。JavaScript 获取伪元素,可以使用下面的方法。
var test = document.querySelector('#test');
var result = window.getComputedStyle(test, ':before').content;
var color = window.getComputedStyle(test, ':before').color;
此外,也可以使用 CSSStyleDeclaration 实例的getPropertyValue
方法,获取伪元素的属性。
var result = window.getComputedStyle(test, ':before')
.getPropertyValue('content');
var color = window.getComputedStyle(test, ':before')
.getPropertyValue('color');
7、StyleSheet 接口
7.1 概述
StyleSheet
接口代表网页的一张样式表,包括<link>
元素加载的样式表和<style>
元素内嵌的样式表。
document
对象的styleSheets
属性,可以返回当前页面的所有StyleSheet
实例(即所有样式表)。它是一个类似数组的对象。
var sheets = document.styleSheets;
var sheet = document.styleSheets[0];
sheet instanceof StyleSheet // true
如果是<style>
元素嵌入的样式表,还有另一种获取StyleSheet
实例的方法,就是这个节点元素的sheet
属性。
// HTML 代码为 <style id="myStyle"></style>
var myStyleSheet = document.getElementById('myStyle').sheet;// 另一种获取styleSheet方式
myStyleSheet instanceof StyleSheet // true
严格地说,StyleSheet
接口不仅包括网页样式表,还包括 XML 文档的样式表。所以,它有一个子类CSSStyleSheet
表示网页的 CSS 样式表。我们在网页里面拿到的样式表实例,实际上是CSSStyleSheet
的实例。这个子接口继承了StyleSheet
的所有属性和方法,并且定义了几个自己的属性,下面把这两个接口放在一起介绍。
7.2 实例属性
StyleSheet
实例有以下属性。
(1)StyleSheet.disabled 样式表是否处于禁用状态,可读写
StyleSheet.disabled
返回一个布尔值,表示该样式表是否处于禁用状态。手动设置disabled
属性为true
,等同于在<link>
元素里面,将这张样式表设为alternate stylesheet
,即该样式表将不会生效。
注意,disabled
属性只能在 JavaScript 脚本中设置,不能在 HTML 语句中设置。
<link rel="alternate stylesheet" href="style.css">
<!--设置了alternate stylesheet表示禁用此样式表-->
<style>
body{font-size: 16px;}
</style>
<script>
console.log(document.styleSheets)
/*
StyleSheetList {}
0: CSSStyleSheet {ownerRule: null, type: "text/css", href: "file:///C:/Users/dell/Desktop/css.css", ownerNode: link, parentStyleSheet: null, …}
1: CSSStyleSheet {ownerRule: null, cssRules: CSSRuleList, rules: CSSRuleList, type: "text/css", href: null, …}
length: 2
*/
console.log(document.styleSheets[0].disabled) // false 未禁用?不能判断样式表设置了alternate?
document.styleSheets[0].disabled = true
console.log(document.styleSheets[0].disabled) // true 已禁用
</script>
(2)Stylesheet.href 返回样式表的网址
Stylesheet.href
返回样式表的网址。对于内嵌样式表,该属性返回null
。该属性只读。
document.styleSheets[0].href
(3)StyleSheet.media 返回一个媒介类数组
StyleSheet.media
属性**返回一个类似数组的对象(MediaList
实例),成员是表示适用媒介的字符串。**表示当前样式表是用于屏幕(screen),还是用于打印(print)或手持设备(handheld),或各种媒介都适用(all)。该属性只读,默认值是screen
。
document.styleSheets[0].media.mediaText
// "all"
MediaList
实例的appendMedium
方法,用于增加媒介;deleteMedium
方法用于删除媒介。
document.styleSheets[0].media.appendMedium('handheld');
document.styleSheets[0].media.deleteMedium('print');
(4)StyleSheet.title 返回样式表的title
属性
StyleSheet.title
属性返回样式表的title
属性。
(5)StyleSheet.type 返回样式表的type
属性
StyleSheet.type
属性返回样式表的type
属性,通常是text/css
。
document.styleSheets[0].type // "text/css"
(6)StyleSheet.parentStyleSheet 返回父样式表,当前样式表是通过@import加载才有值,否则null
CSS 的@import
命令允许在样式表中加载其他样式表。StyleSheet.parentStyleSheet
属性返回包含了当前样式表的那张样式表。如果当前样式表是顶层样式表,则该属性返回null
。
if (stylesheet.parentStyleSheet) {
sheet = stylesheet.parentStyleSheet;
} else {
sheet = stylesheet;
}
(7)StyleSheet.ownerNode 返回样式表所在的DOM节点
StyleSheet.ownerNode
属性返回StyleSheet
对象所在的 DOM 节点,通常是<link>
或<style>
。对于那些由其他样式表引用的样式表,该属性为null
。
// HTML代码为
// <link rel="StyleSheet" href="example.css" type="text/css" />
document.styleSheets[0].ownerNode // [object HTMLLinkElement]
(8)CSSStyleSheet.cssRules 返回一个包含所有css规则的类数组
CSSStyleSheet.cssRules
属性**指向一个类似数组的对象(CSSRuleList
实例),里面每一个成员就是当前样式表的一条 CSS 规则。**使用该规则的cssText
属性,可以得到 CSS 规则对应的字符串。
var sheet = document.querySelector('#styleElement').sheet;
sheet.cssRules[0].cssText
// "body { background-color: red; margin: 20px; }"
sheet.cssRules[1].cssText
// "p { line-height: 1.4em; color: blue; }"
每条 CSS 规则还有一个style
属性,指向一个对象,用来读写具体的 CSS 命令。
cssStyleSheet.cssRules[0].style.color = 'red';
cssStyleSheet.cssRules[1].style.color = 'purple';
(9)CSSStyleSheet.ownerRule 规则所有者
有些样式表是通过@import
规则输入的,它的ownerRule
属性会返回一个CSSRule
实例,代表那行@import
规则。如果当前样式表不是通过@import
引入的,ownerRule
属性返回null
。
7.3 实例方法
(1)CSSStyleSheet.insertRule() 插入css规则
CSSStyleSheet.insertRule
方法用于在当前样式表的插入一个新的 CSS 规则。
var sheet = document.querySelector('#styleElement').sheet;
sheet.insertRule('#block { color: white }', 0);
sheet.insertRule('p { color: red }', 1);
该方法可以接受两个参数,第一个参数是表示 CSS 规则的字符串,这里只能有一条规则,否则会报错。第二个参数是该规则在样式表的插入位置(从0开始),该参数可选,默认为0(即默认插在样式表的头部)。注意,如果插入位置大于现有规则的数目,会报错。
该方法的返回值是新插入规则的位置序号。
注意,浏览器对脚本在样式表里面插入规则有很多限制。所以,这个方法最好放在try...catch
里使用。
(2)CSSStyleSheet.deleteRule() 移除css规则
CSSStyleSheet.deleteRule
方法用来在样式表里面移除一条规则,它的参数是该条规则在cssRules
对象中的位置。该方法没有返回值。
document.styleSheets[0].deleteRule(1);
8、实例:添加样式表
网页添加样式表有两种方式。一种是添加一张内置样式表,即在文档中添加一个<style>
节点。
// 写法一
var style = document.createElement('style');
style.setAttribute('media', 'screen');
style.innerHTML = 'body{color:red}';
document.head.appendChild(style);
// 写法二
var style = (function () {
var style = document.createElement('style');
document.head.appendChild(style);
return style;
})();
style.sheet.insertRule('.foo{color:red;}', 0); // 样式表插入规则
另一种是添加外部样式表,即在文档中添加一个<link>
节点,然后将href
属性指向外部样式表的 URL。
var linkElm = document.createElement('link');
linkElm.setAttribute('rel', 'stylesheet');
linkElm.setAttribute('type', 'text/css');
linkElm.setAttribute('href', 'reset-min.css');
document.head.appendChild(linkElm);
9、CSSRuleList 接口
CSSRuleList 接口是一个类似数组的对象,表示一组 CSS 规则,成员都是 CSSRule 实例。
获取 CSSRuleList 实例,一般是通过StyleSheet.cssRules
属性。
// HTML 代码如下
// <style id="myStyle">
// h1 { color: red; }
// p { color: blue; }
// </style>
var myStyleSheet = document.getElementById('myStyle').sheet;
var crl = myStyleSheet.cssRules;
crl instanceof CSSRuleList // true
CSSRuleList 实例里面,每一条规则(CSSRule 实例)可以通过rules.item(index)
或者rules[index]
拿到。CSS 规则的条数通过rules.length
拿到。还是用上面的例子。
crl[0] instanceof CSSRule // true
crl.length // 2
注意,添加规则和删除规则不能在 CSSRuleList 实例操作,而要在它的父元素 StyleSheet 实例上,通过StyleSheet.insertRule()
和StyleSheet.deleteRule()
操作。
10、CSSRule 接口
10.1 概述
一条 CSS 规则包括两个部分:CSS 选择器和样式声明。下面就是一条典型的 CSS 规则。
.myClass {
color: red;
background-color: yellow;
}
JavaScript 通过 CSSRule 接口操作 CSS 规则。一般通过 CSSRuleList 接口(StyleSheet.cssRules
)获取 CSSRule 实例。
// HTML 代码如下
// <style id="myStyle">
// .myClass {
// color: red;
// background-color: yellow;
// }
// </style>
var myStyleSheet = document.getElementById('myStyle').sheet;
var ruleList = myStyleSheet.cssRules;
var rule = ruleList[0];
rule instanceof CSSRule // true
10.2 CSSRule 实例的属性
(1)CSSRule.cssText
CSSRule.cssText
属性返回当前规则的文本,还是使用上面的例子。
rule.cssText
// ".myClass { color: red; background-color: yellow; }"
如果规则是加载(@import
)其他样式表,cssText
属性返回@import 'url'
。
(2)CSSRule.parentStyleSheet
CSSRule.parentStyleSheet
属性返回当前规则所在的样式表对象(StyleSheet 实例),还是使用上面的例子。
rule.parentStyleSheet === myStyleSheet // true
(3)CSSRule.parentRule
CSSRule.parentRule
属性返回包含当前规则的父规则,如果不存在父规则(即当前规则是顶层规则),则返回null
。
父规则最常见的情况是,当前规则包含在@media
规则代码块之中。
// HTML 代码如下
// <style id="myStyle">
// @supports (display: flex) {
// @media screen and (min-width: 900px) {
// article {
// display: flex;
// }
// }
// }
// </style>
var myStyleSheet = document.getElementById('myStyle').sheet;
var ruleList = myStyleSheet.cssRules;
var rule0 = ruleList[0];
rule0.cssText
// "@supports (display: flex) {
// @media screen and (min-width: 900px) {
// article { display: flex; }
// }
// }"
// 由于这条规则内嵌其他规则,
// 所以它有 cssRules 属性,且该属性是 CSSRuleList 实例
rule0.cssRules instanceof CSSRuleList // true
var rule1 = rule0.cssRules[0];
rule1.cssText
// "@media screen and (min-width: 900px) {
// article { display: flex; }
// }"
var rule2 = rule1.cssRules[0];
rule2.cssText
// "article { display: flex; }"
rule1.parentRule === rule0 // true
rule2.parentRule === rule1 // true
(4)CSSRule.type
CSSRule.type
属性返回一个整数值,表示当前规则的类型。
最常见的类型有以下几种。
- 1:普通样式规则(CSSStyleRule 实例)
- 3:
@import
规则 - 4:
@media
规则(CSSMediaRule 实例) - 5:
@font-face
规则
10.3 CSSStyleRule 接口
如果一条 CSS 规则是普通的样式规则(不含特殊的 CSS 命令),那么除了 CSSRule 接口,它还部署了 CSSStyleRule 接口。
CSSStyleRule 接口有以下两个属性。
(1)CSSStyleRule.selectorText
CSSStyleRule.selectorText
属性返回当前规则的选择器。
var stylesheet = document.styleSheets[0];
stylesheet.cssRules[0].selectorText // ".myClass"
注意,这个属性是可写的。
(2)CSSStyleRule.style
CSSStyleRule.style
属性返回一个对象(CSSStyleDeclaration 实例),代表当前规则的样式声明,也就是选择器后面的大括号里面的部分。
// HTML 代码为
// <style id="myStyle">
// p { color: red; }
// </style>
var styleSheet = document.getElementById('myStyle').sheet;
styleSheet.cssRules[0].style instanceof CSSStyleDeclaration
// true
CSSStyleDeclaration 实例的cssText
属性,可以返回所有样式声明,格式为字符串。
styleSheet.cssRules[0].style.cssText
// "color: red;"
styleSheet.cssRules[0].selectorText
// "p"
10.4 CSSMediaRule 接口
如果一条 CSS 规则是@media
代码块,那么它除了 CSSRule 接口,还部署了 CSSMediaRule 接口。
该接口主要提供media
属性和conditionText
属性。前者返回代表@media
规则的一个对象(MediaList 实例),后者返回@media
规则的生效条件。
// HTML 代码如下
// <style id="myStyle">
// @media screen and (min-width: 900px) {
// article { display: flex; }
// }
// </style>
var styleSheet = document.getElementById('myStyle').sheet;
styleSheet.cssRules[0] instanceof CSSMediaRule
// true
styleSheet.cssRules[0].media
// {
// 0: "screen and (min-width: 900px)",
// appendMedium: function,
// deleteMedium: function,
// item: function,
// length: 1,
// mediaText: "screen and (min-width: 900px)"
// }
styleSheet.cssRules[0].conditionText
// "screen and (min-width: 900px)"
11、window.matchMedia()
11.1 基本用法
window.matchMedia
方法用来将 CSS 的MediaQuery
条件语句,转换成一个 MediaQueryList 实例。
var mdl = window.matchMedia('(min-width: 400px)');
mdl instanceof MediaQueryList // true
上面代码中,变量mdl
就是 mediaQueryList 的实例。
注意,如果参数不是有效的MediaQuery
条件语句,window.matchMedia
不会报错,依然返回一个 MediaQueryList 实例。
window.matchMedia('bad string') instanceof MediaQueryList // true
11.2 MediaQueryList 接口的实例属性
MediaQueryList 实例有三个属性。
(1)MediaQueryList.media
MediaQueryList.media
属性返回一个字符串,表示对应的 MediaQuery 条件语句。
var mql = window.matchMedia('(min-width: 400px)');
mql.media // "(min-width: 400px)"
(2)MediaQueryList.matches
MediaQueryList.matches
属性返回一个布尔值,表示当前页面是否符合指定的 MediaQuery 条件语句。
if (window.matchMedia('(min-width: 400px)').matches) {
/* 当前视口不小于 400 像素 */
} else {
/* 当前视口小于 400 像素 */
}
下面的例子根据mediaQuery
是否匹配当前环境,加载相应的 CSS 样式表。
var result = window.matchMedia("(max-width: 700px)");
if (result.matches){
var linkElm = document.createElement('link');
linkElm.setAttribute('rel', 'stylesheet');
linkElm.setAttribute('type', 'text/css');
linkElm.setAttribute('href', 'small.css');
document.head.appendChild(linkElm);
}
(3)MediaQueryList.onchange
如果 MediaQuery 条件语句的适配环境发生变化,会触发change
事件。MediaQueryList.onchange
属性用来指定change
事件的监听函数。该函数的参数是change
事件对象(MediaQueryListEvent 实例),该对象与 MediaQueryList 实例类似,也有media
和matches
属性。
var mql = window.matchMedia('(max-width: 600px)');
mql.onchange = function(e) {
if (e.matches) {
/* 视口不超过 600 像素 */
} else {
/* 视口超过 600 像素 */
}
}
上面代码中,change
事件发生后,存在两种可能。一种是显示宽度从700像素以上变为以下,另一种是从700像素以下变为以上,所以在监听函数内部要判断一下当前是哪一种情况。
11.3 MediaQueryList 接口的实例方法
MediaQueryList 实例有两个方法MediaQueryList.addListener()
和MediaQueryList.removeListener()
,用来为change
事件添加或撤销监听函数。
var mql = window.matchMedia('(max-width: 600px)');
// 指定监听函数
mql.addListener(mqCallback);
// 撤销监听函数
mql.removeListener(mqCallback);
function mqCallback(e) {
if (e.matches) {
/* 视口不超过 600 像素 */
} else {
/* 视口超过 600 像素 */
}
}
注意,MediaQueryList.removeListener()
方法不能撤销MediaQueryList.onchange
属性指定的监听函数。
12、本章小结
本章当中的实例(接口)有:
CSSStyleDeclaration接口(css样式声明): 用来操作元素的样式
StyleSheet接口(样式表): 代表网页的一张样式表,包括<link>
元素加载的样式表和<style>
元素内嵌的样式表。
CSSRuleList接口(css规则列表): 一个类似数组的对象,表示一组 CSS 规则,成员都是 CSSRule 实例。
CSSRule接口(css规则): JavaScript 通过 CSSRule 接口操作 CSS 规则。一般通过 CSSRuleList 接口(StyleSheet.cssRules
)获取 CSSRule 实例。
CSSStyleRule接口: 如果一条 CSS 规则是普通的样式规则(不含特殊的 CSS 命令),那么除了 CSSRule 接口,它还部署了 CSSStyleRule 接口。
CSSMediaRule 接口: 如果一条 CSS 规则是@media
代码块,那么它除了 CSSRule 接口,还部署了 CSSMediaRule 接口。
九、Mutation Observer API 监视DOM变动
1、概述
Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。
概念上,它很接近事件,可以理解为 DOM 发生变动就会触发 Mutation Observer 事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说,DOM 的变动立刻会触发相应的事件;Mutation Observer 则是异步触发,DOM 的变动并不会马上触发,而是要等到当前所有 DOM 操作都结束才触发。
这样设计是为了应付 DOM 变动频繁的特点。举例来说,如果文档中连续插入1000个<p>
元素,就会连续触发1000个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;而 Mutation Observer 完全不同,只在1000个段落都插入结束后才会触发,而且只触发一次。
Mutation Observer 有以下特点。
- 它等待所有脚本任务完成后,才会运行(即异步触发方式)。
- 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动。
- 它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。
2、MutationObserver 构造函数 (使用方式)
使用时,首先使用MutationObserver
构造函数,新建一个观察器实例,同时指定这个实例的回调函数。
var observer = new MutationObserver(callback);
上面代码中的回调函数,会在每次 DOM 变动后调用。该回调函数接受两个参数,第一个是变动数组,第二个是观察器实例,下面是一个例子。
var observer = new MutationObserver(function (mutations, observer) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
});
3、MutationObserver 的实例方法
3.1 observe()
observe
方法用来启动监听,它接受两个参数。
- 第一个参数:所要观察的 DOM 节点
- 第二个参数:一个配置对象,指定所要观察的特定变动
var article = document.querySelector('article');
var options = { // 配置对象,用于observer参数二,配置指定观察的特定变动
'childList': true, // 子节点变动
'attributes':true, // 属性变动
'characterData': true // 节点内容或节点文本的变动
} ;
observer.observe(article, options);
上面代码中,observe
方法接受两个参数,第一个是所要观察的DOM元素是article
,第二个是所要观察的变动类型(子节点变动和属性变动)。
观察器所能观察的 DOM 变动类型(即上面代码的options
对象),有以下几种。
- childList:子节点的变动(指新增,删除或者更改)。
- attributes:属性的变动。
- characterData:节点内容或节点文本的变动。
想要观察哪一种变动类型,就在option
对象中指定它的值为true
。需要注意的是,必须同时指定childList
、attributes
和characterData
中的一种或多种,若未均指定将报错。
除了变动类型,options
对象还可以设定以下属性:
subtree
:布尔值,表示是否将该观察器应用于该节点的所有后代节点。attributeOldValue
:布尔值,表示观察attributes
变动时,是否需要记录变动前的属性值。characterDataOldValue
:布尔值,表示观察characterData
变动时,是否需要记录变动前的值。attributeFilter
:数组,表示需要观察的特定属性(比如['class','src']
)。
// 开始监听文档根节点(即<html>标签)的变动
mutationObserver.observe(document.documentElement, {
attributes: true, // 属性变动
characterData: true, // 节点内容或节点文本的变动
childList: true, // 子节点的变动
subtree: true, // 是否将该观察器应用于该节点的所有后代节点
attributeOldValue: true, // 观察attributes变动时,是否需要记录变动前的属性值
characterDataOldValue: true // 观察characterData变动时,是否需要记录变动前的值。
});
对一个节点添加观察器,就像使用addEventListener
方法一样,多次添加同一个观察器是无效的,回调函数依然只会触发一次。如果指定不同的options
对象,以后面添加的那个为准,类似覆盖。
下面的例子是观察新增的子节点。
var insertedNodes = [];
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
for (var i = 0; i < mutation.addedNodes.length; i++) {
insertedNodes.push(mutation.addedNodes[i]);
}
});
console.log(insertedNodes);
});
observer.observe(document, { childList: true, subtree: true });
3.2 disconnect(),takeRecords()
disconnect
方法用来停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器。
observer.disconnect();
takeRecords
方法用来清除变动记录,即不再处理未处理的变动。该方法返回变动记录的数组。
observer.takeRecords();
下面是一个例子。
// 保存所有没有被观察器处理的变动
var changes = mutationObserver.takeRecords();
// 停止观察
mutationObserver.disconnect();
4、MutationRecord 对象 (变动记录)
DOM 每次发生变化,就会生成一条变动记录(MutationRecord 实例)。该实例包含了与变动相关的所有信息。Mutation Observer 处理的就是一个个MutationRecord
实例所组成的数组。
MutationRecord
对象包含了DOM的相关信息,有如下属性:
type
:观察的变动类型(attributes
、characterData
或者childList
)。target
:发生变动的DOM节点。addedNodes
:新增的DOM节点。removedNodes
:删除的DOM节点。previousSibling
:前一个同级节点,如果没有则返回null
。nextSibling
:下一个同级节点,如果没有则返回null
。attributeName
:发生变动的属性。如果设置了attributeFilter
,则只返回预先指定的属性。oldValue
:变动前的值。这个属性只对attribute
和characterData
变动有效,如果发生childList
变动,则返回null
。
5、应用示例
5.1 子元素的变动
下面的例子说明如何读取变动记录。
var callback = function (records){
console.log(records) // records参数是 MutationRecord实例
records.map(function(record){
console.log('Mutation type: ' + record.type);
console.log('Mutation target: ' + record.target);
});
};
/*
[MutationRecord]
0: MutationRecord
addedNodes: NodeList [text]
attributeName: null
attributeNamespace: null
nextSibling: null
oldValue: null
previousSibling: script
removedNodes: NodeList []
target: body
type: "childList"
__proto__: MutationRecord
length: 1
__proto__: Array(0)
Mutation type: childList
test.html:23 Mutation target: [object HTMLBodyElement]
*/
var mo = new MutationObserver(callback);
var option = {
'childList': true,
'subtree': true
};
mo.observe(document.body, option);
document.body.append(document.createElement('div').textContent = '123')
上面代码的观察器,观察<body>
的所有下级节点(childList
表示观察子节点,subtree
表示观察后代节点)的变动。回调函数会在控制台显示所有变动的类型和目标节点。
5.2 属性的变动
下面的例子说明如何追踪属性的变动。
var callback = function (records) {
records.map(function (record) {
console.log('Previous attribute value: ' + record.oldValue);
});
};
var mo = new MutationObserver(callback);
var element = document.getElementById('#my_element');
var options = {
'attributes': true,
'attributeOldValue': true
}
mo.observe(element, options);
上面代码先设定追踪属性变动('attributes': true
),然后设定记录变动前的值。实际发生变动时,会将变动前的值显示在控制台。
5.3 取代 DOMContentLoaded 事件
网页加载的时候,DOM 节点的生成会产生变动记录,因此只要观察 DOM 的变动,就能在第一时间触发相关事件,也就没有必要使用DOMContentLoaded
事件。
var observer = new MutationObserver(callback);
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
上面代码中,监听document.documentElement
(即网页的<html>
HTML 节点)的子节点的变动,subtree
属性指定监听还包括后代节点。因此,任意一个网页元素一旦生成,就能立刻被监听到。
封装一个监听 DOM 生成的函数
下面的代码,使用MutationObserver
对象封装一个监听 DOM 生成的函数。
(function(win){
'use strict';
var listeners = [];
var doc = win.document;
var MutationObserver = win.MutationObserver || win.WebKitMutationObserver;
var observer;
function ready(selector, fn){
// 储存选择器和回调函数
listeners.push({
selector: selector,
fn: fn
});
if(!observer){
// 监听document变化
observer = new MutationObserver(check);
observer.observe(doc.documentElement, {
childList: true,
subtree: true
});
}
// 检查该节点是否已经在DOM中
check();
}
function check(){
// 检查是否匹配已储存的节点
for(var i = 0; i < listeners.length; i++){
var listener = listeners[i];
// 检查指定节点是否有匹配
var elements = doc.querySelectorAll(listener.selector);
for(var j = 0; j < elements.length; j++){
var element = elements[j];
// 确保回调函数只会对该元素调用一次
if(!element.ready){
element.ready = true;
// 对该节点调用回调函数
listener.fn.call(element, element);
}
}
}
}
// 对外暴露ready
win.ready = ready;
})(this);
// 使用方法
ready('.foo', function(element){
// ...
});
- 点赞
- 收藏
- 关注作者
评论(0)