search
HomeWeb Front-endH5 TutorialImplementing editor undo and rollback operations based on the new HTML5 feature Mutation Observer_html5 tutorial skills

Introduction to MutationObserver

MutationObserver provides developers with the ability to respond appropriately when the DOM tree within a certain range changes. This API is designed to replace the Mutation event introduced in the DOM3 event specification.

Mutation Observer is an interface for monitoring DOM changes. Mutation Observer will be notified when any changes occur in the DOM object tree.

Mutation Observer has the following features:

•It waits for all script tasks to be completed before running, that is, in an asynchronous manner
•It encapsulates DOM change records into an array for processing instead of processing DOM changes one by one.
•It can observe all changes that occur in DOM nodes, and it can also observe a certain type of changes

MDN information: MutationObserver

MutationObserver is a constructor, so when creating it, you need to pass new MutationObserver;

When instantiating MutationObserver, a callback function is required. The callback function will be called when the specified DOM node (target node) changes.

When called, the observer object will be passed to the function with two parameters:

 1: The first parameter is an array containing several MutationRecord objects;

 2: The second parameter is the observer object itself.

For example:

 

Copy code
The code is as follows:

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

observer methods

The instance observer has three methods: 1: observe ; 2: disconnect ; 3: takeRecords ;

observe method

Observe method: Register the target node that needs to be observed to the current observer object, and receive a notification when the DOM changes in the target node (you can also observe its descendant nodes at the same time);

This method requires two parameters, the first is the target node, and the second parameter is the type that needs to be monitored for changes, which is a json object. The example is as follows:

 

Copy code
The code is as follows:

observer.observe( document.body, {
'childList': true, //The child elements of this element are added or deleted
'subtree': true, //All the child elements of this element are added or deleted
'attributes' : true, //Listen for attribute changes
'characterData' : true, //Listen for text or comment changes
'attributeOldValue' : true, //Original value of attribute
'characterDataOldValue' : true
});

disconnect method

The disconnect method will stop observing the properties and node changes of the target node until the observe method is called again next time;

takeRecords

Clear the record queue of the observer object and return an array containing the Mutation event object;

MutationObserver is perfect for implementing redo and undo of an editor, because any changes that occur within the specified node will be recorded every time. If you use traditional keydown or keyup implementation, there will be some disadvantages, such as:

1: Loss of scrolling, resulting in inaccurate scroll position;

2: Lost focus;
....
It took a few hours to write a management plug-in MutationJS for undo and redo (management of undo and rollback) implemented through MutationObserver, which can be used as a Separate plug-in introduction: (http://files.cnblogs.com/files/diligenceday/MutationJS.js):


Copy code
The code is as follows:

/**
* @desc MutationJs, uses DOM3's new event MutationObserve; by listening to specified node elements, listens for changes in internal dom attributes or dom nodes, and executes corresponding callbacks;
**/
window.nono = window.nono || {};
/**
* @desc
**/
nono.MutationJs = function( dom ) {
//Uniform compatibility issues
var MutationObserver = this.MutationObserver = window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver;
//Determine whether the browser is or Whether to support MutationObserver;
this.mutationObserverSupport = !!MutationObserver;
//By default, listen for changes in child elements, attributes of child elements, and attribute values;
this.options = {
'childList': true,
'subtree' : true,
'attributes' : true,
'characterData' : true,
'attributeOldValue' : true,
'characterDataOldValue' : true
} ;
//This saves the instance of MutationObserve;
this.muta = {};
//The list variable saves the user's operations;
this.list = [];
//The current rollback index
this.index = 0;
//If there is no dom, it will listen to body by default;
this.dom = dom|| document.documentElement.body || document. getElementsByTagName("body")[0];
//Start monitoring immediately;
this.observe( );
};
$.extend(nono.MutationJs.prototype, {
//Callback for node changes, you need to save redo and undo to the list;
"callback" : function ( records , instance ) {
//You need to clear the ones behind the index;
this .list.splice( this.index 1 );
var _this = this;
records.map(function(record) {
var target = record.target;
console.log(record) ;
//Delete or add elements;
if( record.type === "childList" ) {
//If you delete elements;
if(record.removedNodes.length ! == 0) {
//Get the relative index of the element;
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 elements are added;
};
if(record.addedNodes.length !== 0) {
//Get the relative index of the element;
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, indexes);
_this.reObserve();
}
});
};
//@desc What the hell is characterData;
//ref: http:// baike.baidu.com/link?url=Z3Xr2y7zIF50bjXDFpSlQ0PiaUPVZhQJO7SaMCJXWHxD6loRcf_TVx1vsG74WUSZ_0-7wq4_oq0Ci-8ghUAG8a
}else if( record.type === "characterData" ) {
var oldValue = record. oldValue;
var newValue = record .target.textContent //|| record.target.innerText, is not prepared to handle IE789 compatibility, so innerText is not needed;
_this.list.push({
"undo" : function() {
_this.disconnect();
target.textContent = oldValue;
_this.reObserve();
},
"redo" : function () {
_this.disconnect();
target.textContent = newValue;
_this.reObserve();
}
});
//If the attributes change, style, dataset, attribute all belong to attributes changes, you can Unified processing;
}else if( record.type === "attributes" ) {
var oldValue = Record.oldValue;
var newValue = Record.target.getAttribute( Record.attributeName );
var attributeName = Record.attributeName;
_this.list.push({
"실행 취소" : function() {
_this.disconnect();
target.setAttribute(attributeName, oldValue);
_this.reObserve();
},
"redo" : function() {
_this.disconnect();
target.setAttribute(attributeName, newValue);
_this.reObserve();
}
});
};
} );
//중신설设置索引;
this.index = this.list.length-1;
},
"removeChildren" : 함수( 대상, 노드 ) {
for( var i= 0, len= node.length; i target.removeChild( node[i] );
};
},
"addChildren": 함수( 대상, 노드, 인덱스) {
for(var i= 0, len= 노드.길이; 나는 if(target.children[ indexs[i] ]) {
target.insertBefore( 노드[i] , target.children[ 인덱스[i] ]) ;
}else{
target.appendChild( 노드[i] );
};
};
},
//快捷방법,사용来判断child재父元素的哪个节点上;
" indexOf": 함수(target, obj) {
return Array.prototype.indexOf.call(target, obj)
},
"getIndexs": 함수(target, objs) {
var 결과 = [];
for(var i=0; i result.push( this.indexOf(target, objs[i]) );
};
return result;
},
/**
* @desc는 청취 객체를 지정합니다
**/
"observe" : function( ) {
if( this.dom.nodeType !== 1) return Alert("参数不对,第一个参数应该为一个dom节点");
this.muta = new this.MutationObserver( this.callback.bind(this) );
//马上开始监听;
this .muta.observe( this.dom, this.options );
},
/**
* @desc 재시작 모니터링;
**/
"reObserve" : 함수 () {
this.muta.observe( this.dom, this.options );
},
/**
*@desc는 DOM 작업을 기록하지 않으며 이 함수 내의 모든 작업은 실행 취소 및 다시 실행 목록에 기록되지 않습니다.
**/
"without" : function ( fn ) {
this.disconnect();
fn&fn ();
this.reObserve();
},
/**
* @desc 모니터링 취소;
**/
"disconnect" : function () {
return this.muta.disconnect() ;
},
/**
* @desc Mutation 작업을 목록에 저장합니다.
**/
"save" : function ( obj ) {
if(!obj.undo)return warning("传进来的第一个参数必须 유 실행 취소 방법 실행");
if(!obj.redo)return 경고("传进来的第一个参数必须유재실행 방법 실행");
this.list.push(obj) ;
},
/**
* @desc ;
**/
"reset" : function () {
//清空数组;
this.list = [];
this .index = 0;
},
/**
* @desc 지정된 인덱스 뒤의 작업을 삭제합니다.
**/
"splice" : 함수( 인덱스 ) {
this.list.splice( 인덱스 );
},
/**
* @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": 함수() {
return this.index !== -1;
},
/**
* @desc는 재작동 가능 여부를 결정합니다.
**/
"canRedo": 함수() {
return this.list.length-1 !== this.index;
}
});

MutationJS如何使사용

那么这个MutationJS如何使사용呢?


复代码
代码如下:

//This is to instantiate a MutationJS object. If no parameters are passed, it will monitor changes in the body element by default;
mu = new nono.MutationJs();
//You can pass a specified element. For example:
mu = new nono.MutationJS( document.getElementById("div0") );
//Then all element changes under this element will be recorded by the plug-in;

Mutation instance mu has several methods:

1: mu.undo() operation rollback;

2: mu.redo() Undo rollback;

3: Whether mu.canUndo() can operate back, the return value is true or false;

4: Whether mu.canRedo() can cancel the rollback, the return value is true or false;

5: mu.reset() clears all undo lists and releases space;

6: mu.without() passes a function parameter, and all DOM operations inside the function will not be recorded by mu;

MutationJS implements a simple undoManager for reference, which runs perfectly on Firefox, Chrome, Google Chrome, and IE11:


Copy code
The code is as follows:












MutationObserver is for replacement Remove the original series of Mutation Events, and the browser will monitor the addition, deletion, replacement, etc. of all elements under the specified Element;



;
;

;



<script><br /> window.onload = function () {<br /> window.mu = new nono.MutationJs();<br /> //Cancel monitoring<br /> mu.disconnect();<br /> //Restart monitoring<br /> mu.reObserve(); <br /> document.getElementById("b0").addEventListener("click", function ( ev ) {<br /> div = document.createElement("div");<br /> div.innerHTML = document.getElementById("value ").value;<br /> document.getElementById("div").appendChild( div );<br /> });<br /> document.getElementById("prev").addEventListener("click", function ( ev ) {<br /> mu.undo();<br /> });<br /> document.getElementById("next").addEventListener("click", function ( ev ) {<br /> mu.redo();<br /> });<br /> };<br /></script>


Screenshot of DEMO under IE:

Browser compatibility of MutatoinObserver:

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

webkit

26

14(14) 11 15 6.0WebKit

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Understanding H5: The Meaning and SignificanceUnderstanding H5: The Meaning and SignificanceMay 11, 2025 am 12:19 AM

H5 is HTML5, the fifth version of HTML. HTML5 improves the expressiveness and interactivity of web pages, introduces new features such as semantic tags, multimedia support, offline storage and Canvas drawing, and promotes the development of Web technology.

H5: Accessibility and Web Standards ComplianceH5: Accessibility and Web Standards ComplianceMay 10, 2025 am 12:21 AM

Accessibility and compliance with network standards are essential to the website. 1) Accessibility ensures that all users have equal access to the website, 2) Network standards follow to improve accessibility and consistency of the website, 3) Accessibility requires the use of semantic HTML, keyboard navigation, color contrast and alternative text, 4) Following these principles is not only a moral and legal requirement, but also amplifying user base.

What is the H5 tag in HTML?What is the H5 tag in HTML?May 09, 2025 am 12:11 AM

The H5 tag in HTML is a fifth-level title that is used to tag smaller titles or sub-titles. 1) The H5 tag helps refine content hierarchy and improve readability and SEO. 2) Combined with CSS, you can customize the style to enhance the visual effect. 3) Use H5 tags reasonably to avoid abuse and ensure the logical content structure.

H5 Code: A Beginner's Guide to Web StructureH5 Code: A Beginner's Guide to Web StructureMay 08, 2025 am 12:15 AM

The methods of building a website in HTML5 include: 1. Use semantic tags to define the web page structure, such as, , etc.; 2. Embed multimedia content, use and tags; 3. Apply advanced functions such as form verification and local storage. Through these steps, you can create a modern web page with clear structure and rich features.

H5 Code Structure: Organizing Content for ReadabilityH5 Code Structure: Organizing Content for ReadabilityMay 07, 2025 am 12:06 AM

A reasonable H5 code structure allows the page to stand out among a lot of content. 1) Use semantic labels such as, etc. to organize content to make the structure clear. 2) Control the rendering effect of pages on different devices through CSS layout such as Flexbox or Grid. 3) Implement responsive design to ensure that the page adapts to different screen sizes.

H5 vs. Older HTML Versions: A ComparisonH5 vs. Older HTML Versions: A ComparisonMay 06, 2025 am 12:09 AM

The main differences between HTML5 (H5) and older versions of HTML include: 1) H5 introduces semantic tags, 2) supports multimedia content, and 3) provides offline storage functions. H5 enhances the functionality and expressiveness of web pages through new tags and APIs, such as and tags, improving user experience and SEO effects, but need to pay attention to compatibility issues.

H5 vs. HTML5: Clarifying the Terminology and RelationshipH5 vs. HTML5: Clarifying the Terminology and RelationshipMay 05, 2025 am 12:02 AM

The difference between H5 and HTML5 is: 1) HTML5 is a web page standard that defines structure and content; 2) H5 is a mobile web application based on HTML5, suitable for rapid development and marketing.

HTML5 Features: The Core of H5HTML5 Features: The Core of H5May 04, 2025 am 12:05 AM

The core features of HTML5 include semantic tags, multimedia support, form enhancement, offline storage and local storage. 1. Semantic tags such as, improve code readability and SEO effect. 2. Multimedia support simplifies the process of embedding media content through and tags. 3. Form Enhancement introduces new input types and verification properties, simplifying form development. 4. Offline storage and local storage improve web page performance and user experience through ApplicationCache and localStorage.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool