监视DOM元素变动:MutationObserver

MutationObserver

MutationObserver:变动观察器,监视DOM元素的所有变动,包括节点的增减、属性的变动、文本内容的变动;
注:类似于事件,做了一个对应操作,触发对应事件的执行,但是它们有着根本之间的区别:事件的执行时同步的,触发的同时,每个事件依次执行,但是observer是异步触发的,等到所有dom操作结束,再执行。

MutationEvent

MutationObserver是在DOM4规范中定义的,它的前身是MutationEvent事件,该事件最初在DOM2事件规范中介绍,到来了DOM3事件规范中正式定义,但是由于该事件存在兼容性以及性能上的问题被弃用。

MutationEvent总共有7种事件:DOMNodeInserted、DOMNodeRemoved、DOMSubtreeModified、DOMAttrModified、DOMCharacterDataModified、DOMNodeInsertedIntoDocument、DOMNodeRemovedFromDocument

MutationEvent的兼容性:
  1. MutationEvent在IE浏览器中最低支持到IE9;
  2. 在webkit内核的浏览器中,不支持 DOMAttrModified 事件;
  3. IE,Edge以及Firefox浏览器下不支持 DOMNodeInsertedIntoDocument 和 DOMNodeRemovedFromDocument事件;
缺点:

1,MutationEvent中的所有事件都被设计成无法取消,如果可以取消MutationEvent事件则会导致现有的DOM接口无法对文档进行改变,比如appendChild,remove等添加和删除节点的DOM操作。
2,document下的所有DOM添加操作都会触发DOMNodeInserted方法,这时就会出现循环调用DOMNodeInserted方法,导致浏览器崩溃
3,还有就是MutationEvent是事件机制,因此会有一般事件都存在的捕获和冒泡阶段,此时如果在捕获和冒泡阶段又对DOM进行了操作会拖慢浏览器的运行。
4,MutationEvent事件机制是同步的,也就是说每次DOM修改就会触发,修改几次就触发几次,严重降低浏览器的运行,严重时甚至导致线程崩溃

目的:

应付 DOM 频繁的变动

特点:

  • 异步执行,它等待所有脚本任务完成后,才会运行;
  • 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动;
  • 它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动;

observe(DOM, options)

1, DOM 为要监听的节点
2, options 可以配置要监听的具体内容
3, 可以调用多次 observe ,同时监听多个 DOM 的变动。

{ 
 attributeFilter: ['data-name'], // 要监听的特定属性数组
attributeOldValue: true, // MutationRecords 中是否记录属性变动的旧值
 attributes: true, // 是否监听属性变化
characterData: true, // 是否监听字符变化
characterDataOldValue: true, // MutationRecords 中是否记录字符串变动的旧值
childList: true, // 是否监听子字节点的新增删除
subtree: true, // 监听范围扩展为节点树中所有的节点,否则只监听子节点的变动
}

disconnct()

取消当前的监听,取消之后又可以通过 observe 再次监听

takeRecords()

callback 的触发是异步的, 可能出现虽然监测到了变动记录,但是还没有调用 callback 处理, takeRecords 可以取出当前所有未处理的 MutationRcords 。一般情况用在要调用 disconnect 之前,一次取出所有的记录,并且处理。

MutationRecord

MutationRecord 是一次变动的记录;

MutationRecord {
	 type, // 变动类型,值有 attributes(属性变动),characterData(字符变动),childList(子节点删除,新增)
	 target, // 变动影响的 Node, 如果 type = attributes, 则是 属性变动的 Node 
            // 如果 type = characterData, 则是 字符修改的 TextNode
            // 如果 type = childList, 则是 父节点
	 addedNodes, // 增加的节点,如果没有则为空数组
	 removedNodes, // 删除的节点,如果没有则为空数组
	 previousSibling, // 删除/增加节点的 前一个节点
	 nextSibling, // 删除/增加节点的 前一个节点
	 attributeName, // 变动的属性名
	 attributeNamespace, // 变动属性的namespace
	oldValue, // 变动的老的值  如果 type = attributes, 则是 属性修改前的值
            // 如果 type = characterData, 则是 字符修改前的值
            // 如果 type = childList, 则是 null            
}

优点

很方便的监听节点所有或特定的变化

缺点

回调的触发时异步的。click 等事件触发是同步的。

应用

实际场景:使用vant 中fileld组件的多文本框属性,进入页面时隐藏,点击按钮触发显示,此时多行文本框高度只有一行且超出有滑条,而不会自适应高度。
解决方案:显示多行文本框时刷新页面

// 观察dom对象变动
export function observeDom( el, cb, options = {
    attributes: true,
    subtree: true,
    attributeOldValue: true
  }) {
 	 const observer = new MutationObserver(cb);
 	 observer.observe(el, options);
}
// 监控变动的dom
observeDom(this.$refs.moreDom, () => {
    	this.$refs[i].adjustSize(); // adjustSize()方法是由vant提供的自适应高度方法
}, {
     attributes: true,
      subtree: false,
      attributeOldValue: true
    });
posted @ 2021-01-12 17:41  85号bobo  阅读(711)  评论(0编辑  收藏  举报