深入學習jquery原始碼之detach()和clone()
阿新 • • 發佈:2018-12-31
深入學習jquery原始碼之detach()和clone()
detach([expr])
概述
從DOM中刪除所有匹配的元素。
這個方法不會把匹配的元素從jQuery物件中刪除,因而可以在將來再使用這些匹配的元素。與remove()不同的是,所有繫結的事件、附加的資料等都會保留下來。
引數
expr String
用於篩選元素的jQuery表示式
從DOM中把所有段落刪除
<p>Hello</p> how are <p>you?</p>
$("p").detach();
how are
從DOM中把帶有hello類的段落刪除
<p class="hello">Hello</p> how are <p>you?</p>
$("p").detach(".hello");
how are <p>you?</p>
clone([Even[,deepEven]])
概述
克隆匹配的DOM元素並且選中這些克隆的副本。
在想把DOM文件中元素的副本新增到其他位置時這個函式非常有用。
引數
Events Boolean
一個布林值(true 或者 false)指示事件處理函式是否會被複制。V1.5以上版本預設值是:false
Events[,deepEvents] Boolean,Boolean
1:一個布林值(true 或者 false)指示事件處理函式是否會被複制。
2:一個布林值,指示是否對事件處理程式和克隆的元素的所有子元素的資料應該被複制。
克隆所有b元素(並選中這些克隆的副本),然後將它們前置到所有段落中。
<b>Hello</b><p>, how are you?</p>
$("b").clone().prependTo("p");
<b>Hello</b><p><b>Hello</b>, how are you?</p>
建立一個按鈕,他可以複製自己,並且他的副本也有同樣功能。
<button>Clone Me!</button>
$("button").click(function(){
$(this).clone(true).insertAfter(this);
});
jquery原始碼
/**
* Clean-up method for dom ready events
*/
function detach() {
if (document.addEventListener) {
document.removeEventListener("DOMContentLoaded", completed, false);
window.removeEventListener("load", completed, false);
} else {
document.detachEvent("onreadystatechange", completed);
window.detachEvent("onload", completed);
}
}
/**
* The ready event handler and self cleanup method
*/
function completed() {
// readyState === "complete" is good enough for us to call the dom ready in oldIE
if (document.addEventListener || event.type === "load" || document.readyState === "complete") {
detach();
jQuery.ready();
}
}
// Mark scripts as having already been evaluated
function setGlobalEval(elems, refElements) {
var elem,
i = 0;
for (; (elem = elems[i]) != null; i++) {
jQuery._data(elem, "globalEval", !refElements || jQuery._data(refElements[i], "globalEval"));
}
}
jQuery.extend({
cache: {},
// The following elements (space-suffixed to avoid Object.prototype collisions)
// throw uncatchable exceptions if you attempt to set expando properties
noData: {
"applet ": true,
"embed ": true,
// ...but Flash objects (which have this classid) *can* handle expandos
"object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
},
// For internal use only.
_data: function (elem, name, data) {
return internalData(elem, name, data, true);
},
_removeData: function (elem, name) {
return internalRemoveData(elem, name, true);
}
});
jQuery.fn.extend({
remove: function (selector, keepData /* Internal Use Only */) {
var elem,
elems = selector ? jQuery.filter(selector, this) : this,
i = 0;
for (; (elem = elems[i]) != null; i++) {
if (!keepData && elem.nodeType === 1) {
jQuery.cleanData(getAll(elem));
}
if (elem.parentNode) {
if (keepData && jQuery.contains(elem.ownerDocument, elem)) {
setGlobalEval(getAll(elem, "script"));
}
elem.parentNode.removeChild(elem);
}
}
return this;
},
clone: function (dataAndEvents, deepDataAndEvents) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map(function () {
return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
});
},
detach: function (selector) {
return this.remove(selector, true);
}
});
function internalData(elem, name, data, pvt /* Internal Use Only */) {
if (!jQuery.acceptData(elem)) {
return;
}
var ret, thisCache,
internalKey = jQuery.expando,
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
isNode = elem.nodeType,
// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
cache = isNode ? jQuery.cache : elem,
// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
id = isNode ? elem[internalKey] : elem[internalKey] && internalKey;
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
if ((!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string") {
return;
}
if (!id) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if (isNode) {
id = elem[internalKey] = deletedIds.pop() || jQuery.guid++;
} else {
id = internalKey;
}
}
if (!cache[id]) {
// Avoid exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
cache[id] = isNode ? {} : { toJSON: jQuery.noop };
}
// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
if (typeof name === "object" || typeof name === "function") {
if (pvt) {
cache[id] = jQuery.extend(cache[id], name);
} else {
cache[id].data = jQuery.extend(cache[id].data, name);
}
}
thisCache = cache[id];
// jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
if (!pvt) {
if (!thisCache.data) {
thisCache.data = {};
}
thisCache = thisCache.data;
}
if (data !== undefined) {
thisCache[jQuery.camelCase(name)] = data;
}
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
if (typeof name === "string") {
// First Try to find as-is property data
ret = thisCache[name];
// Test for null|undefined property data
if (ret == null) {
// Try to find the camelCased property
ret = thisCache[jQuery.camelCase(name)];
}
} else {
ret = thisCache;
}
return ret;
}
function getAll(context, tag) {
var elems, elem,
i = 0,
found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName(tag || "*") :
typeof context.querySelectorAll !== strundefined ? context.querySelectorAll(tag || "*") :
undefined;
if (!found) {
for (found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++) {
if (!tag || jQuery.nodeName(elem, tag)) {
found.push(elem);
} else {
jQuery.merge(found, getAll(elem, tag));
}
}
}
return tag === undefined || tag && jQuery.nodeName(context, tag) ?
jQuery.merge([context], found) :
found;
}