1. 概述
Mutation Observer
是用于代替Mutation events
作为观察DOM树结构发生变化时,做出相应处理的API;- 为什么要使用
Mutation Observer
去代替Mutation Events
呢?我们先了解一下Mutation Events
;
Mutation Events
Mutation Events
是在DOM3中定义的,用于监听DOM
树结构变化的事件;Mutation Events
列表:DOMAttrModified
DOMAttributeNameChanged
DOMCharacterDataModified
DOMElementNameChanged
DOMNodeInserted
DOMNodeRemoved
DOMNodeInsertedIntoDocument
DOMSubtreeModified
- 其中
DOMNodeRemoved
、DOMNodeInserted
和DOMSubtreeModified
分别用于监听元素子项的删除、新增、修改(包括删除和新增); DOMAttrModified
是监听元素属性的修改,并且能够提供具体的修改动作;
- 用法如下: js代码解读复制代码
document.getElementById('list').addEventListener("DOMSubtreeModified", function(){ console.log('列表中子元素被修改'); }, false);
Mutation Events
遇到的问题:- 浏览器兼容性问题:
IE9
不支持Mutation Events
;Webkit
内核不支持DOMAttrModified
特性;DOMElementNameChanged
和DOMAttributeNameChanged
在Firefox
上不被支持;
- 性能问题:
Mutation Events
是同步执行的:- 它的每次调用,都需要从事件队列中取出事件并执行,然后事件队列中移除,期间需要移动队列元素;
- 如果事件触发的较为频繁的话,每一次都需要执行上面的这些步骤,那么浏览器会被拖慢;
Mutation Events
本身是事件,所以捕获是采用的是事件冒泡的形式;- 如果冒泡捕获期间又触发了其他的
Mutation Events
的话,很有可能就会导致阻塞Javascript
线程,甚至导致浏览器崩溃;
- 如果冒泡捕获期间又触发了其他的
- 浏览器兼容性问题:
2.1 Event() 构造函数
Event()
构造函数, 创建一个新的事件对象 Event
。
语法
javascript代码解读复制代码event = new Event(typeArg, eventInit);
参数
typeArg
: 是DOMString
类型,表示所创建事件的名称。eventIni
(可选):是EventInit
类型的字典,接受以下字段:"bubbles"
,可选,Boolean
类型,默认值为false
,表示该事件是否冒泡。"cancelable"
,可选,Boolean
类型,默认值为false
, 表示该事件能否被取消。"composed"
,可选,Boolean
类型,默认值为false
,指示事件是否会在影子DOM根节点之外触发侦听器。
2.2 EventTarget.dispatchEvent
向一个指定的事件目标派发一个事件, 并以合适的顺序同步调用目标元素相关的事件处理函数。标准事件处理规则(包括事件捕获和可选的冒泡过程)同样适用于通过手动的使用dispatchEvent()
方法派发的事件。
语法
javascript代码解读复制代码cancelled = !target.dispatchEvent(event)
参数
event
是要被派发的事件对象。target
被用来初始化 事件 和 决定将会触发 目标.
返回值
- 当该事件是可取消的(cancelable为true)并且至少一个该事件的 事件处理方法 调用了
Event.preventDefault()
,则返回值为false
;否则返回true
。
如果该被派发的事件的事件类型(event's type)在方法调用之前没有被经过初始化被指定,就会抛出一个 UNSPECIFIED_EVENT_TYPE_ERR
异常,或者如果事件类型是null
或一个空字符串. event handler 就会抛出未捕获的异常; 这些 event handlers 运行在一个嵌套的调用栈中: 他们会阻塞调用直到他们处理完毕,但是异常不会冒泡。
同步调用
与浏览器原生事件不同,原生事件是由DOM派发的,并通过事件循环(event loop)异步调用事件处理程序,而dispatchEvent()
则是同步调用事件处理程序。在调用dispatchEvent()
后,所有监听该事件的事件处理程序将在代码继续前执行并返回。
dispatchEvent()
是create-init-dispatch过程的最后一步,用于将事件调度到实现的事件模型中。可以使用 Event 构造函数来创建事件。
JavaScript代码解读复制代码var event = new Event('build');
// Listen for the event.
elem.addEventListener('build', function (e) {
console.log('build');
}, false);
// Dispatch the event.
elem.dispatchEvent(event);
自定义事件其实就是通过JavaScript代码来触发事件目标上注册的某个监听器,dispatchEvent(event)
其实就类似于我们点击鼠标然后触发click
事件处理程序。
MutationObserver
动态监听dom元素的变化
MutationObserver
接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。
const cb = (mutations) => {
mutations.forEach((element) => {
console.log(element);
});
};
var observer = new MutationObserver(cb);
observer.observe(el, {
subtree: true,
attributes: true,
childList: true,
});
observer
开始监听调用方法
- el, 需要监听的dom对象
- options
- subtree
boolean
元素下的所有子节点的添加删除、属性变化等 - attributes
boolean
属性变化 - attributeFilter
array
需要筛选的属性值数组 - attributeOldValue
boolean
属性变化的旧值 - childList
boolean
子孙节点的添加或删除 - characterData
boolean
节点中值的变化监听 - characterDataOldValue
boolean
节点中值的变化监听
- subtree
disconnect
手动取消监听
takeRecords
获取所有已变更列表,但是还没有被回调函数调用的记录, 并清空之前的记录 此方法最常见的使用场景是在断开观察者之前立即获取所有未处理的更改记录,以便在停止观察者时可以处理任何未处理的更改。
使用
- 监听Dom变化
- 使用其执行微任务
observer
和 Promise.then
一样,属于micro task
Vue nextTick
源码中使用方式
let callbacks = []
function flushCallback() {
let copys = callbacks.copy(); // copy arrays
let fn = copys.shift()
while(copys.length > 0) {
fn()
}
}
let runFunc = () => {}
if(hasPromise) { // 如果有Promise, 优先使用Promsie
let p = Promise.resolve()
runFunc = () => {
p.then(flushCallback)
}
}
else if(hasMutationObserver) { // 如果有MutationObserver
let count = 1
let el = document.createTextNode(String(count))
let o = new MutationObserver(flushCallback)
o.observer(el, {
characterData: true // 监听字符变化
})
runFunc = () => {
count = (count + 1) % 2
el.data = String(count) // 改变字符,以触发执行微任务
}
}
// ....
const nextTick = (fn, ctx) => {
callbacks.push(() => {
// 更改调用上下文
fn.call(ctx)
})
runFunc()
}
其内部实现,其实就是微任务的执行机制
Comments | NOTHING