Dom operations include append, Prepend, before, after, ReplaceWith, Appendto, Prependto, InsertBefore, InsertAfter, ReplaceAll. Its core processing function is Dommanip.
The last five methods used in the DOM operator function are still the first five methods, source
Jquery.each ({
appendto: "Append", Prependto: "Prepend", InsertBefore: "
before",
InsertAfter: " After ",
ReplaceAll:" replacewith "
}, function (name, original) {
jquery.fn[name] = function (selector) {
var Elems,
i = 0,
ret = [],
insert = JQuery (selector), last
= insert.length-1;
for (; I <= last; i++) {
Elems = i = = last? This:this.clone (true);
JQuery (Insert[i]) [Original] (elems);
Modern browser invoke apply will take the jquery object as an array, but older versions of IE need to use. Get ()
core_push.apply (ret, elems.get ());
}
Return This.pushstack (ret);
};
There are two ways in which browsers native insert nodes: AppendChild and Inserbefore,jquery Use these two methods to expand the following methods
JQuery.fn.append use This.appendchild (elem)
JQuery.fn.prepend use This.insertbefore (Elem, This.firstchild)
JQuery.fn.before use This.parentNode.insertBefore (Elem, this);
JQuery.fn.after use This.parentNode.insertBefore (Elem, this.nextsibling);
JQuery.fn.replaceWith use This.parentNode.insertBefore (Elem, this.nextsibling);
Look at an example of the source code (jQuery.fn.append)
Append:function () {return
This.dommanip (arguments, True, function (elem) {
if (This.nodetype = 1 | | this.nod EType = = 11 | | This.nodetype = = 9) {
this.appendchild (elem);}}
);
According to the above source code. Guessing Dommanip's role is to iterate through the elements that match the current jquery object, then each element invokes the incoming callback and the node to be inserted (if it is a string that requires the creation of a document fragment node) as an argument to the incoming callback, and the incoming callback is executed.
Then analyze the Dommanip to see if the guesses are correct. Dom is the DOM element, MANIP is the acronym for manipulate, and the literal meaning of the combination is DOM manipulation.
A. dommanip:function (args, table, callback) parsing
Args DOM element or HTML code to be inserted
Whether the table needs to be modified tbody, this variable is the result of the optimization
Callback callback function, execution format is Callback.call (target element is context, document fragment to insert/single DOM element)
First look at the process, then look at the details
The first step is to initialize the variable. Where Inoclone is used later, if the current jquery object matches more than one element (n > 1), meaning that the constructed document fragment needs to be used by N, then it needs to be cloned (n-1), and the fragmented document itself is enough n times used; is the first element of the first parameter args, followed by a special treatment of value as a function;
var-I, node, hasscripts,
scripts, doc, fragment,
i = 0,
l = this.length,
set = this,
Inoclone = l -1,
value = args[0],
isfunction = jquery.isfunction (value);
The second step is to deal with the special one by one call Dommanip that will match the current jquery object. There are two kinds of special cases: first, if the incoming node is a function (that is, value is a function), then each element that the current jquery object matches needs to be treated as a node in the Dommanip by the value computed by the function. The second, WebKit, we cannot clone the document fragment containing checked, the cloned document cannot be reused, then only one of each element matched by the current jquery object is invoked once Dommanip processing.
WebKit, we can't clone the text containing checked fragment
if (Isfunction | |! (L <= 1 | | typeof value!== "string" | | jQuery.support.checkClo NE | | !rchecked.test (value)) {return
This.each (function (index) {
var self = set.eq (index);
If args[0] is a function, the execution function returns the result replaces the original args[0]
if (isfunction) {
args[0] = Value.call (this, index, table? self.html (): undefined);
}
Self.dommanip (args, table, callback);}
The third step is to handle the normal situation by using the incoming node to build the document fragment and insert it into the document. The document fragments built in this need to be reused and differentiated from the second process. It should be noted that if the script node needs to be executed after the load completes. Follow the source sequence to see the process
Building Document Fragmentation
fragment = Jquery.buildfragment (args, this[0].ownerdocument, False, this);
i = Fragment.firstchild;
if (fragment.childNodes.length = = 1) {
fragment = i
}
Isolate the script, which has a function disablescript changes the type value of the script label to ensure security, the original type value is "Text/javascript", changed to "True/text/javascript" or "False/text/javascript"
Scripts = Jquery.map (GetAll (Fragment, "script"), disablescript);
hasscripts = Scripts.length;
Document Fragmentation Insert Page
for (; I < L; i++) {
node = fragment;
if (i!== inoclone) {
node = jquery.clone (node, true, true);
Keep references to cloned scripts for later restoration
if (hasscripts) {
jquery.merge (scripts, GETALL (node , "script");
}
Callback.call (
table && jquery.nodename (this[i], "table")?
Findorappend (This[i], "tbody"):
this[i],
node,
i
);
}
Execute script, in two cases, remote use AJAX to handle, local direct execution.
if (hasscripts) {
doc = scripts[scripts.length-1].ownerdocument;
reenable scripts
jquery.map (scripts, restorescript);
Inserts the first document into the executable script for
(i = 0; i < hasscripts; i++) {
node = scripts[i];
if (rscripttype.test) (Node.type | | "") &&
!jquery._data (node, "Globaleval") && Jquery.contains (doc, node)) {
if (NODE.SRC) { c10/>//Hope Ajax is available
... Jquery.ajax ({
url:node.src,
type: "Get",
dataType: "Script",
Async:false,
Global:false,
"throws": true
});
else {
jquery.globaleval (node.text | | node.textcontent | | | node.innerhtml | | ""). Replace (Rcleanscript, ""));
B. DOM operational expansion
JQuery.fn.text
JQuery.fn.text:function (value) {return
jquery.access (this, function (value) {return
value = = = undefined?
jquery.text (This):
this.empty (). Append ((this[0) && this[0].ownerdocument | | document). createTextNode (value));
}, NULL, value, arguments.length);
Final execution value = = undefined? Jquery.text (This): This.empty (). Append ((this[0) && this[0].ownerdocument | | document). createTextNode (value ) );
Among them jquery.text = Sizzle.gettext;
JQuery.fn.html
function uses jquery.access to handle
JQuery.fn.html:function (value) {return
jquery.access (this, function (value) {...}, null, value, Arguments.length );
}
If no parameter representation is taken
if (value = = = undefined) {return
Elem.nodetype = = 1?
Elem.innerHTML.replace (Rinlinejquery, ""):
undefined;
}
Otherwise see if you can add content with innerHTML. Click on reference compatibility issues
See if we can take a shortcut, just use the innerHTML
//need to execute the code Script|style|link etc cannot be used innerHTML
//htmlserialize: Make sure that the link node can use innerHTML to properly serialize, which needs to be used in the//leadingwhitespace:ie strips of the IE browser's wrapper element
. innerHTML need to start with a blank
// It is not necessary to add an additional end tag or peripheral wrapper label to the element
if (typeof value = = = "string" &&!rnoinnerhtml.test (value) &&
(jQuery). Support.htmlserialize | | !rnoshimcache.test (value)) &&
(JQuery.support.leadingWhitespace | |!rleadingwhitespace.test (value)) &A mp;&
!wrapmap[(rtagname.exec (value) | | ["", ""] ) [1].tolowercase ()]) {
value = Value.replace (Rxhtmltag, "<$1></$2>");
try {
for (; i < L; i++) {
//remove element node and cache, prevent memory leaks
elem = this[i] | | | {};
if (Elem.nodetype = = 1) {
jquery.cleandata (GetAll (Elem, false));
elem.innerhtml = value;
}
}
Elem = 0;
If you use innerHTML to throw an exception, use an alternate method
} catch (e) {}
}
If you cannot use innerHTML or use it unsuccessfully (throw an exception), use an alternate method append
Alternate method, using Append to add node
if (elem) {
this.empty (). Append (value)
;
JQuery.fn.wrapAll (wrapping all matching elements with a single label)
process steps:
incoming arguments are functions that pass function results to
if (jquery.isfunction (HTML)) {return
This.each (function (i) {
jQuery (this). Wrapall (The Html.call (this, i));
});
}
Create a wrap layer
//Get package tag the elements to wrap the target around
var wrap = jQuery (HTML, this[0].ownerdocument). EQ (0). clo NE (true);
if (this[0].parentnode) {
wrap.insertbefore (this[0]);
}
Wrap the current jquery object in a package
Wrap.map (function () {
var elem = this;
while (elem.firstchild && elem.firstChild.nodeType = = 1) {
elem = elem.firstchild;
} return
Elem
}). Append (this);
Note: The current jquery object matching element is best only one, if there are multiple words are not recommended, this situation is carefully used, the following examples can be seen.
The simple example of the original DOM is (use this example later)
<div id= ' center ' class= ' center ' >
<div id= ' ss ' class= ' center ' >
<input type= ' submit ' id= ' left ' Class= "Left" >
</div>
</div>
<div class= "Right" > I'm right</div>
$ (' # Center '). Wrapall ("<p></p>"), Dom becomes
<p>
<div id= "center" class= "Center" >
<div id= "ss" class= "Center" >
<input type= "Submit" id= "left" class= "left" >
</div>
</div>
</p>
<div class= "Right" > I'm right</div>.
Caution: If the current jquery matches more than one element, for example, the original DOM executes $ (' div '). Wrapall ("<p></p>") The result Dom becomes
<p>
<div id= "center" class= "center" ></div>
<div id= "ss" class= "Center" >
<input type= ' submit ' id= ' left ' class= ' left ' >
</div>
<div class= ' right ' > I'm right</div. >
</p>
See the result of it, originally #center is #ss parent node, the result becomes #ss sibling node.
JQuery.fn.wrapInner (The specified HTML structure is wrapped outside all child nodes of each matching element)
Processing steps:
The incoming argument is a function that passes the result of the function
if (jquery.isfunction (HTML)) {return
This.each (the function (i) {
jQuery (this). Wrapinner (Html.call (this, i));
});
Iterate through the jquery object array, get the contents of each element (all child nodes) contents, and then use Warpall to wrap contents
Return This.each (function () {
var self = jQuery (this),
contents = self.contents ();
if (contents.length) {
contents.wrapall (HTML);
} else {
self.append (HTML);}}
);
or using the original DOM in the example above, execute $ (' div '). Wrapinner (' <p></p> ') and the result Dom becomes
<div id= "center" class= "Center" >
<p>
<div id= "ss" class= "Center" >
<p>
<input type= "Submit" id= "left" class= "left" >
</p>
</div>
</p>
</div>
<div class= "right" >
<p>
I'm OK
</p>
</div>
JQuery.fn.wrap (The specified HTML structure is wrapped outside each matching element)
Use Wrapall to wrap each element of jquery separately.
Return This.each (function (i) {
jQuery (this). Wrapall (isfunction? Html.call (This, i): HTML);
};
Row $ (' div '). Wrap (' <p></p> ') The result Dom becomes
<p>
<div id= "center" class= "Center" >
<p>
<div id= "ss" class= "Center" >
<input type= "Submit" id= "left" class= "left" >
</div>
</p>
</div>
</p>
<p>
<div class= "Right" > I'm right</div>
</p>
JQuery.fn.unwrap (Remove the parent element of each matching element)
Use ReplaceWith to replace the parent node of the matching element with all child nodes that match the element's parent node. Of course, the parent node is body/html/document must be removed.
Return This.parent (). each (the function () {
if (!jquery.nodename (this, the "body")) {
jQuery (this). ReplaceWith (Thi s.childnodes);
}
). End ();
Execute $ (' div '). Wrap () result Dom becomes
<div id= "ss" class= "Center" >
<input type= "Submit" id= "left" class= " Left ' >
</div>
<div class= ' right ' > I'm right</div>.
JQuery.fn.remove (removing matching elements from the document)
You can also use selectors to further narrow the range of removal, removing only some elements of the current matching element that match the specified selector.
The Remove () function also removes the additional data (the data () function) and the event handler that are bound to the element Association (detach ()), as opposed to detach ().
for (; (Elem = this[i])!= null; i++) {
if (!selector | | jquery.filter (selector, [Elem]). length > 0) {
//Detach incoming parameter Keepdata is true, cache is not deleted C3/>if (!keepdata && Elem.nodetype = = 1) {
//Clear Cache
Jquery.cleandata (GetAll (elem))
;
if (elem.parentnode) {
if (keepdata && jquery.contains (elem.ownerdocument, Elem)) {
Setglobaleval (g Etall (Elem, "script");
}
Elem.parentNode.removeChild (Elem);}}
You can see that there is an important function cleandata, which is used to clear the cache: iterate through each node element and handle each node element:
1. Get the cache corresponding to the current element
id = elem[Internalkey];
data = ID && cache[ID];
2. If there are bound events, traverse the Unbind event
if (data.events) {
for (type in data.events) {
if (special[type]) {
jQuery.event.remove (elem, type);
//This is a shortcut to avoid jQuery.event.remove overhead
} else {
jquery.removeevent (elem, type, data.handle);}}}
3. If the cache is not removed by JQuery.event.remove, manually remove the cache. Which IE needs to do some compatibility processing, and will eventually save the history of deletion as Core_deletedids
Remove Cache
if (cache[ID) {
delete cache[id] When jQuery.event.remove has not removed cache;
IE does not allow deletion of expando features from the node using delete,
//can also use RemoveAttribute functions on file nodes;
We have to deal with all of these cases,
if (deleteexpando) {
delete elem[Internalkey];
} else if (typeof Elem.removeattribute !== core_strundefined) {
elem.removeattribute (internalkey);
} else {
elem[internalkey] = null;
}
Core_deletedids.push (ID);
}
JQuery.fn.detach
Detach:function (selector) {return
This.remove (selector, true);
},
JQuery.fn.empty (clears all content within each matching element (all child nodes))
function will remove all child nodes of each matching element, including text nodes, annotation nodes, and all types of nodes, and the corresponding cached data will be emptied.
for (; (Elem = this[i])!= null; i++) {
///Prevent memory leaks from removing element node cache
if (Elem.nodetype = = 1) {
jquery.cleandata (GetAll (Elem, false));
}
Remove all child nodes while
(elem.firstchild) {
elem.removechild (elem.firstchild);
}
The Ie<9,select node needs to have option empty
if (elem.options && jquery.nodename (elem, "select")) {
elem.options . length = 0;
}
}