js mutationobserver简要介绍

观察者模式介绍

观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,
全部依赖于它的对象都获得通知并自动刷新。

一些好的文章
观察者模式与委托模式的区别
深刻理解JavaScript系列(32):设计模式之观察者模式
【Javascript设计模式3】-观察者模式javascript

MutationObserver介绍

可使用的配置html

  • childList: *true =========================能够观察子元素
  • attributes: *true ========================能够观察属性
  • characterData: *true ====================能够观察数据
  • subtree: *true =========================能够观察全部后代
  • attributeOldValue: *true ==================能够保存属性旧值
  • characterDataOldValue: ==================*true 能够保存数据旧值
  • attributeFilter: ==========================设置指定观察属性元素集合

note: Mutation Observers 被限制能够观察Dom序列化状态 在观察textarea内内容改变时 没法触发java

observe 一个被观察者对象 一份配置node

void observe(
  Node target,
  MutationObserverInit options
);

disconnet 断开观察者与目标连接segmentfault

void disconnect();

takeRecords 返回对象全部观察记录设计模式

Array takeRecords();

MutationObserver使用

不一样浏览器之间存在兼容性问题数组

var MutationObserver = window.MutationObserver 
|| window.WebKitMutationObserver 
|| window.MozMutationObserver;

html浏览器

<ol contenteditable oninput="">
    <li>Press enter and look at the console</li>
  </ol>

获取list domapp

var list = document.querySelector('ol');

实例化MutationObserverdom

var Observer = new MutationObserver(function(mutations){
});

Mutation Observer 对象

图片描述

监测childList

Observer.observe(list, {
  childList: true
});

不过值得注意的是 这里观测的是list直接child 若是要观测child的child 就须要开启subtree
好比要检测这样的行为

list.childNodes[0].appendChild(document.createElement('div'));

observer须要更改配置

Observer.observe(list, {
  childList: true,
  subtree: true
});

(mutationObserver观测childlist) jsbin地址

observe 常见配置 及其解释

observer.observe(target, {childList:true,subtree:true})                 
//subtree属性让观察行为进行"递归",这时,以target节点为根节点的整棵DOM树发生的变化均可能会被观察到 
observer.observe(document, {childList:true,subtree:true})               
//若是target为document或者document.documentElement,则当前文档中全部的节点添加与删除操做都会被观察到
observer.observe(document, {childList:true,attributes:true,characterData:true,subtree:true})   
//当前文档中几乎全部类型的节点变化都会被观察到(包括属性节点的变化和文本节点的变化等)

observe 观察characterData

Observer.observe(list, {childList:true});  
//假设此时target的outHTML内容为<div>foo<div>,则: 
list.childNodes[0].data = "bar";           
//不会触发回调函数,由于childList只观察节点的新建与删除,
而这里target节点的子节点仍然只有一个,没有多,没有少
Observer.observe(list, {
childList:true,characterData:true});        
//加上characterData属性,容许观察文本节点的变化,行不行? 
list.childNodes[0].data = "sds";            
//仍是不会触发回调函数,由于发生变化的是target节点的子节点,咱们目前的目标节点只有一个,就是target.
Observer.observe(list, {
childList:true,characterData:true,subtree:true});  
//加上subtree属性,观察全部后代节点 
list.childNodes[0].data = "cha";

(mutationObserver观测characterdata) jsbin地址

observe 观察attribute

Observer.observe(list, {attributes:true});                    
//只观察目标节点的属性节点
list.setAttribute("foo","bar");        
//无论foo属性存在不存在,都会触发回调函数
list.setAttribute("foo","bar");        
//即便先后两次的属性值同样,仍是会触发回调函数
list.removeAttribute("foo");            
//移除foo属性节点,触发回调函数
list.removeAttribute("foo");            
//不会触发回调函数,由于已经没有属性节点可移除了
Observer.observe(list, {attributes:true,attributeFilter:["bar"]});     
//指定要观察的属性名
list.setAttribute("foo","bar");        
//不会触发回调函数,由于attributeFilter数组不包含"foo"
list.setAttribute("bar","foo");

(mutationObserver观测attribute) jsbin地址

咱们开始作一个编辑器

功能 向前 向后而且按钮要能随时改变

ol设置为contenteditable时,当每次敲击回车时,ol的children会增长一个li 而且咱们构造一个observer监听它子元素的变化, 这样咱们即可以得到每次改变后全部新的children

var observer = new MutationObserver(function(mutations) {  
    mutations.forEach(function(mutation) {
      if (mutation.type === 'childList') {
        var list_values = [].slice.call(list.children) 
            .map( function(node) { return node.innerHTML; }) 
            .filter( function(s) {
              if (s === '<br>') {
                return false;
              }
              else {
                return true;
              }
         });
        console.log(list_values);
      }
    });
  });

  observer.observe(list, {
    attributes: true, 
    childList: true, 
    characterData: true
  });

(观察ol子元素的变化) jsbin地址

编辑器对与每行变化也须要监测, 咱们能够本身构造一个entry保存每次数据

var observer = new MutationObserver(function (mutations) {
    // Whether you iterate over mutations..
    mutations.forEach(function (mutation) {
      // or use all mutation records is entirely up to you
      var entry = {
        mutation: mutation,
        el: mutation.target,
        value: mutation.target.textContent,
        oldValue: mutation.oldValue
      };
      console.log('Recording mutation:', entry);
    });
  });

(ol监测每一行变化) jsbin地址

编辑器统计字数

var observer = new  MutationObserver(function(mutations){ mutations.forEach(function(mutation){
    if(mutation.type == "characterData") {
    var newValue = mutation.target.textContent;
      textinputcount.innerHTML = "还能够输入"+(1000 - newValue.length+"字");
    }
  });

编辑器统计字数

相关文章
相关标签/搜索