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+"字");
    }
  });

編輯器統計字數

相關文章
相關標籤/搜索