觀察者設計模式定義了對象間的一種一對多的依賴關係,以便一個對象的狀態發生變化時, 全部依賴於它的對象都獲得通知並自動刷新。
一些好的文章
觀察者模式與委託模式的區別
深刻理解JavaScript系列(32):設計模式之觀察者模式
【Javascript設計模式3】-觀察者模式javascript
可使用的配置html
note: Mutation Observers 被限制能夠觀察Dom序列化狀態 在觀察textarea內內容改變時 沒法觸發java
observe 一個被觀察者對象 一份配置node
void observe( Node target, MutationObserverInit options );
disconnet 斷開觀察者與目標連接segmentfault
void disconnect();
takeRecords 返回對象全部觀察記錄設計模式
Array takeRecords();
不一樣瀏覽器之間存在兼容性問題數組
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 });
編輯器對與每行變化也須要監測, 咱們能夠本身構造一個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); }); });
編輯器統計字數
var observer = new MutationObserver(function(mutations){ mutations.forEach(function(mutation){ if(mutation.type == "characterData") { var newValue = mutation.target.textContent; textinputcount.innerHTML = "還能夠輸入"+(1000 - newValue.length+"字"); } });