根据HTML5新特点Mutation Observer完成编写器的撤消和

日期:2020-10-11 类型:科技新闻 

关键词:如何制作微信小程序,微信小程序源码,小程序码生成,凡科网微信小程序,微信公众号小程序

MutationObserver详细介绍

MutationObserver给开发设计者们出示了1种能在某个范畴内的DOM树产生转变时作出适度反映的工作能力.该API设计方案用来更换掉在DOM3恶性事件标准中引进的Mutation恶性事件.

Mutation Observer(变化观查器)是监控DOM变化的插口。当DOM目标树产生任何变化时,Mutation Observer会获得通告。

Mutation Observer有下列特性:

 •它等候全部脚本制作每日任务进行后,才会运作,即选用多线程方法
 •它把DOM变化纪录封裝成1个数字能量数组开展解决,而并不是1条条地某些解决DOM变化。
 •它便可以观查产生在DOM连接点的全部变化,还可以观查某1类变化

MDN的材料: MutationObserver

MutationObserver是1个结构涵数, 因此建立的情况下要根据 new MutationObserver;

案例化MutationObserver的情况下必须1个回调函数涵数,该回调函数涵数会在特定的DOM连接点(总体目标连接点)产生转变时被启用,

在启用时,观查者目标会 发送给该涵数 两个主要参数:

    1:第1个主要参数是个包括了若干个MutationRecord目标的数字能量数组;

    2:第2个主要参数则是这个观查者目标自身.

例如这样:

     

拷贝编码
编码以下:

var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});

observer的方式

案例observer有3个方式: 1: observe  ;2: disconnect ; 3: takeRecords   ;

observe方式

observe方式:给当今观查者目标申请注册必须观查的总体目标连接点,在总体目标连接点(还能够另外观查其子孙后代连接点)产生DOM转变时收到通告;

这个方式必须两个主要参数,第1个为总体目标连接点, 第2个主要参数为必须监视转变的种类,是1个json目标,  案例以下:

       

拷贝编码
编码以下:

observer.observe( document.body, {
'childList': true, //该元素的子元素新增或删掉
'subtree': true, //该元素的全部子元素新增或删掉
'attributes' : true, //监视特性转变
'characterData' : true, // 监视text或comment转变
'attributeOldValue' : true, //特性初始值
'characterDataOldValue' : true
});

disconnect方式

disconnect方式会终止观查总体目标连接点的特性和连接点转变, 直至下一次再次启用observe方式;

takeRecords

清空 观查者目标的 纪录序列,并回到1个数字能量数组, 数字能量数组中包括Mutation恶性事件目标;

MutationObserver完成1个编写器的redo和undo再合适但是了, 由于每次特定连接点內部产生的任何更改都会被纪录下来, 假如应用传统式的keydown或keyup完成会有1些缺点,例如:

1:丧失翻转, 致使翻转部位禁止确;

2:丧失聚焦点;
....
用了几小时的時间,写了1个根据MutationObserver完成的 undo 和 redo (撤消返回的管理方法)的管理方法软件 MutationJS ,   能够做为1个独立的软件引进:(http://files.cnblogs.com/files/diligenceday/MutationJS.js):


拷贝编码
编码以下:

/**
* @desc MutationJs, 应用了DOM3的新恶性事件 MutationObserve; 根据监视特定连接点元素, 监视內部dom特性或dom连接点的变更, 并实行相应的回调函数;
* */
window.nono = window.nono || {};
/**
* @desc
* */
nono.MutationJs = function( dom ) {
//统1适配难题
var MutationObserver = this.MutationObserver = window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver;
//分辨访问器是或否适用MutationObserver;
this.mutationObserverSupport = !!MutationObserver;
//默认设置监视子元素, 子元素的特性, 特性值的更改;
this.options = {
'childList': true,
'subtree': true,
'attributes' : true,
'characterData' : true,
'attributeOldValue' : true,
'characterDataOldValue' : true
};
//这个储存了MutationObserve的案例;
this.muta = {};
//list这个自变量储存了客户的实际操作;
this.list = [];
//当今返回的数据库索引
this.index = 0;
//假如沒有dom的话,就默认设置监视body;
this.dom = dom|| document.documentElement.body || document.getElementsByTagName("body")[0];
//立刻刚开始监视;
this.observe( );
};
$.extend(nono.MutationJs.prototype, {
//连接点产生更改的回调函数, 要把redo和undo都储存到list中;
"callback" : function ( records , instance ) {
//要把数据库索引后边的给清空;
this.list.splice( this.index+1 );
var _this = this;
records.map(function(record) {
var target = record.target;
console.log(record);
//删掉元素或是加上元素;
if( record.type === "childList" ) {
//假如是删掉元素;
if(record.removedNodes.length !== 0) {
//获得元素的相对性数据库索引;
var indexs = _this.getIndexs(target.children , record.removedNodes );
_this.list.push({
"undo" : function() {
_this.disconnect();
_this.addChildren(target, record.removedNodes ,indexs );
_this.reObserve();
},
"redo" : function() {
_this.disconnect();
_this.removeChildren(target, record.removedNodes );
_this.reObserve();
}
});
//假如是加上元素;
};
if(record.addedNodes.length !== 0) {
//获得元素的相对性数据库索引;
var indexs = _this.getIndexs(target.children , record.addedNodes );
_this.list.push({
"undo" : function() {
_this.disconnect();
_this.removeChildren(target, record.addedNodes );
_this.reObserve();
},
"redo" : function () {
_this.disconnect();
_this.addChildren(target, record.addedNodes ,indexs);
_this.reObserve();
}
});
};
//@desc characterData是甚么鬼;
//ref : http://baike.baidu.com/link?url=Z3Xr2y7zIF50bjXDFpSlQ0PiaUPVZhQJO7SaMCJXWHxD6loRcf_TVx1vsG74WUSZ_0⑺wq4_oq0Ci⑻ghUAG8a
}else if( record.type === "characterData" ) {
var oldValue = record.oldValue;
var newValue = record.target.textContent //|| record.target.innerText, 禁止备解决IE789的适配,因此无需innerText了;
_this.list.push({
"undo" : function() {
_this.disconnect();
target.textContent = oldValue;
_this.reObserve();
},
"redo" : function () {
_this.disconnect();
target.textContent = newValue;
_this.reObserve();
}
});
//假如是特性转变的话style, dataset, attribute全是属于attributes产生更改, 能够统1解决;
}else if( record.type === "attributes" ) {
var oldValue = record.oldValue;
var newValue = record.target.getAttribute( record.attributeName );
var attributeName = record.attributeName;
_this.list.push({
"undo" : function() {
_this.disconnect();
target.setAttribute(attributeName, oldValue);
_this.reObserve();
},
"redo" : function () {
_this.disconnect();
target.setAttribute(attributeName, newValue);
_this.reObserve();
}
});
};
});
//再次设定数据库索引;
this.index = this.list.length⑴;
},
"removeChildren" : function ( target, nodes ) {
for(var i= 0, len= nodes.length; i<len; i++ ) {
target.removeChild( nodes[i] );
};
},
"addChildren" : function ( target, nodes ,indexs) {
for(var i= 0, len= nodes.length; i<len; i++ ) {
if(target.children[ indexs[i] ]) {
target.insertBefore( nodes[i] , target.children[ indexs[i] ]) ;
}else{
target.appendChild( nodes[i] );
};
};
},
//便捷方式,用来分辨child在父元素的哪一个连接点上;
"indexOf" : function ( target, obj ) {
return Array.prototype.indexOf.call(target, obj)
},
"getIndexs" : function (target, objs) {
var result = [];
for(var i=0; i<objs.length; i++) {
result.push( this.indexOf(target, objs[i]) );
};
return result;
},
/**
* @desc 特定监视的目标
* */
"observe" : function( ) {
if( this.dom.nodeType !== 1) return alert("主要参数不对,第1个主要参数应当为1个dom连接点");
this.muta = new this.MutationObserver( this.callback.bind(this) );
//立刻刚开始监视;
this.muta.observe( this.dom, this.options );
},
/**
* @desc 再次刚开始监视;
* */
"reObserve" : function () {
this.muta.observe( this.dom, this.options );
},
/**
*@desc 不纪录dom实际操作, 全部在这个涵数內部的实际操作不容易纪录到undo和redo的目录中;
* */
"without" : function ( fn ) {
this.disconnect();
fn&fn();
this.reObserve();
},
/**
* @desc 撤销监视;
* */
"disconnect" : function () {
return this.muta.disconnect();
},
/**
* @desc 储存Mutation实际操作到list;
* */
"save" : function ( obj ) {
if(!obj.undo)return alert("传进来的第1个主要参数务必有undo方式才行");
if(!obj.redo)return alert("传进来的第1个主要参数务必有redo方式才行");
this.list.push(obj);
},
/**
* @desc ;
* */
"reset" : function () {
//清空数字能量数组;
this.list = [];
this.index = 0;
},
/**
* @desc 把特定index后边的实际操作删掉;
* */
"splice" : function ( index ) {
this.list.splice( index );
},
/**
* @desc 往回走, 撤销返回
* */
"undo" : function () {
if( this.canUndo() ) {
this.list[this.index].undo();
this.index--;
};
},
/**
* @desc 往前走, 再次实际操作
* */
"redo" : function () {
if( this.canRedo() ) {
this.index++;
this.list[this.index].redo();
};
},
/**
* @desc 分辨是不是能够撤消实际操作
* */
"canUndo" : function () {
return this.index !== ⑴;
},
/**
* @desc 分辨是不是能够再次实际操作;
* */
"canRedo" : function () {
return this.list.length⑴ !== this.index;
}
});

MutationJS怎样应用

那末这个MutationJS怎样应用呢?


拷贝编码
编码以下:

//这个是案例化1个MutationJS目标, 假如不传主要参数默认设置监视body元素的变化;
mu = new nono.MutationJs();
//能够传1个特定元素,例如这样;
mu = new nono.MutationJS( document.getElementById("div0") );
//那末全部该元素下的元素变化都会被软件纪录下来;

Mutation的案例mu有几个方式:

1:mu.undo()  实际操作返回;

2:mu.redo()   撤消返回;

3:mu.canUndo() 是不是能够实际操作返回, 回到值为true或false;

4:mu.canRedo() 是不是能够撤消返回, 回到值为true或false;

5:mu.reset() 清空全部的undo目录, 释放出来室内空间;

6:mu.without() 传1个为涵数的主要参数, 全部在该涵数內部的dom实际操作, mu不做纪录;

MutationJS完成了1个简单的 undoManager 出示参照,在火狐和chrome,谷歌访问器,IE11上面运作彻底一切正常:


拷贝编码
编码以下:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF⑻">
<title></title>
<script src="http://cdn.bootcss.com/jquery/1.9.0/jquery.js"></script>
<script src="http://files.cnblogs.com/files/diligenceday/MutationJS.js"></script>
</head>
<body>
<div>
<p>
MutationObserver是以便更换掉原先Mutation Events的1系列恶性事件, 访问器会监视特定Element下全部元素的新增,删掉,更换等;
</p>
<div style="padding:20px;border:1px solid #f00">
<input type="button" value="撤消实际操作" id="prev">;
<input type="button" value="撤消实际操作返回" id="next">;
</div>
<input type="button" value="加上连接点" id="b0">;
<input value="text" id="value">
<div id="div"></div>
</div>
<script>
window.onload = function () {
window.mu = new nono.MutationJs();
//撤销监视
mu.disconnect();
//再次监视
mu.reObserve();
document.getElementById("b0").addEventListener("click", function ( ev ) {
div = document.createElement("div");
div.innerHTML = document.getElementById("value").value;
document.getElementById("div").appendChild( div );
});
document.getElementById("prev").addEventListener("click", function ( ev ) {
mu.undo();
});
document.getElementById("next").addEventListener("click", function ( ev ) {
mu.redo();
});
};
</script>
</body>
</html>

DEMO在IE下的截图:

MutatoinObserver的访问器适配性:

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari Basic support
18

webkit

26

14(14) 11 15 6.0WebKit