观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时, 全部依赖于它的对象都获得通知并自动刷新。
一些好的文章
观察者模式与委托模式的区别
深刻理解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+"字"); } });