MutationObserver监听DOM结构变化
前面有IntersectionObserver观察器实现页面懒加载的功能,原理就是观察dom是否进入视口。那么如果不管是否可见或者要实现随时监听,则需要使用MutationObserver。
示例代码:
1 filterObserve: function(_id) { 2 if ($("#"+_id+" form t-form-item").length<5) return null 3 //选择一个需要观察的节点 4 var targetNode = document.getElementById(_id); 5 // var targetNode = document.getElementsByClassName('query-searchBox')[0]//多页面 6 // 设置observer的配置选项 7 var config = { childList: true,attributes: false, subtree: true//, characterData: true 8 }; 9 10 // 当节点发生变化时的需要执行的函数 11 var callback = function(mutationsList, observer) { 12 for(var mutation of mutationsList) { 13 if (mutation.type == 'childList') { 14 // console.error('A child node has been added or removed.'); 15 // 已展开,直接不设最大高度(或者500) 16 if ($(".searchBox-box .icon-retract")[0]) { 17 $("#"+_id).css("max-height", 'unset') 18 } 19 else// 已折叠,只计算第一行的高度 20 if ($(".searchBox-box .icon-retractno")[0]) { 21 var mHeight = 0 22 $("#"+_id+" form t-form-item").each((index, el)=>{// TODO,待优化,提示文字内容变化的情况下,怎么获取到变化前的高度?变化后大,则不再遍历;变化后小,则遍历 23 if ($(el).find('t-form-explain')[0] && index<4) { 24 mHeight = Math.max(mHeight, $(el).find('t-form-explain').height()) 25 } 26 }) 27 $("#"+_id).css("max-height", 36+mHeight+'px')//$("#querySearchBox").height() 28 } 29 } 30 } 31 }; 32 33 // 创建一个observer示例与回调函数相关联 34 var observer = new MutationObserver(callback); 35 36 //使用配置文件对目标节点进行观测 37 observer.observe(targetNode, config); 38 return observer 39 }, 40 filterDisObserve: function(observer) { 41 if (observer) observer.disconnect(); 42 }
背景:
监听搜索框内的dom变化,以便动态调整框的高度。因为有展开和折叠的功能,所以使用动态调整高度的方案(也可以通过显示或隐藏可折叠区来控制,如此一来就不需要关心高度计算问题了,相对更加合理,后边有该方案的改法)。
使用:
在页面dom加载完成后建立观察者,在页面销毁时进行注销
1 ngAfterViewInit() { 2 // this.toggleFilter() 3 this.filterObserver = ngtpAdapt.filterObserve("querySearchBoxCommonList") 4 } 5 ngOnDestroy() { 6 ngtpAdapt.filterDisObserve(this.filterObserver) 7 }
方案二:
去除高度限制,在展开折叠时控制第4项之后的表单元素的显隐
1 ngAfterViewInit() { 2 this.toggleFilter() 3 // this.filterObserver = ngtpAdapt.filterObserve("querySearchBoxCommonList") 4 } 5 // ngOnDestroy() { 6 // ngtpAdapt.filterDisObserve(this.filterObserver) 7 // } 8 toggleFilter() { 9 ngtpAdapt.showHideFilter(this.showQueryMore=!this.showQueryMore) 10 }
1 showHideFilter: function(bol) { 2 $(".query-searchBox form t-form-item").each((index, el)=>{ 3 if (index>3) { 4 $(el)[bol?'show':'hide']() 5 } 6 }) 7 }
补充:
config
是一个具有布尔选项的对象,该布尔选项表示“将对哪些更改做出反应”:
childList
——node
的直接子节点的更改,subtree
——node
的所有后代的更改,attributes
——node
的特性(attribute),attributeFilter
—— 特性名称数组,只观察选定的特性。characterData
—— 是否观察node.data
(文本内容),
其他几个选项:
attributeOldValue
—— 如果为true
,则将特性的旧值和新值都传递给回调(参见下文),否则只传新值(需要attributes
选项),characterDataOldValue
—— 如果为true
,则将node.data
的旧值和新值都传递给回调(参见下文),否则只传新值(需要characterData
选项)。
然后,在发生任何更改后,将执行“回调”:更改被作为一个 MutationRecord 对象列表传入第一个参数,而观察器自身作为第二个参数。
MutationRecord 对象具有以下属性:
type
—— 变动类型,以下类型之一:"attributes"
:特性被修改了,"characterData"
:数据被修改了,用于文本节点,"childList"
:添加/删除了子元素。
target
—— 更改发生在何处:"attributes"
所在的元素,或"characterData"
所在的文本节点,或"childList"
变动所在的元素,addedNodes/removedNodes
—— 添加/删除的节点,previousSibling/nextSibling
—— 添加/删除的节点的上一个/下一个兄弟节点,attributeName/attributeNamespace
—— 被更改的特性的名称/命名空间(用于 XML),oldValue
—— 之前的值,仅适用于特性或文本更改,如果设置了相应选项attributeOldValue
/characterDataOldValue
。
有一个方法可以停止观察节点:
observer.disconnect()
—— 停止观察。
当我们停止观察时,观察器可能尚未处理某些更改。在种情况下,我们使用:
observer.takeRecords()
—— 获取尚未处理的变动记录列表,表中记录的是已经发生,但回调暂未处理的变动。
这些方法可以一起使用
FIGHTING