- 浏览: 62375 次
文章分类
最新评论
jquery源码系列:append方法实现过程
no1:
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery ); //调用第二步init方法
},
no2:
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// The body element only exists once, optimize finding it
if ( selector === "body" && !context && document.body ) {
this.context = document;
this[0] = document.body;
this.selector = selector;
this.length = 1;
return this;
}
// Handle HTML strings
if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}
// Verify a match, and that no context was specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
doc = ( context ? context.ownerDocument || context : document );
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
ret = rsingleTag.exec( selector );
if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}
return jQuery.merge( this, selector );
// HANDLE: $("#id")
} else {
elem = document.getElementById( match[2] );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
return jQuery.makeArray( selector, this );
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
jquery: "1.7.1",
// The default length of a jQuery object is 0
length: 0,
// The number of elements contained in the matched element set
size: function() {
return this.length;
},
toArray: function() {
return slice.call( this, 0 );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
return num == null ?
// Return a 'clean' array
this.toArray() :
// Return just the object
( num < 0 ? this[ this.length + num ] : this[ num ] );
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
var ret = this.constructor();
if ( jQuery.isArray( elems ) ) {
push.apply( ret, elems );
} else {
jQuery.merge( ret, elems );
}
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) {
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function( callback, args ) {
return jQuery.each( this, callback, args );
},
ready: function( fn ) {
// Attach the listeners
jQuery.bindReady();
// Add the callback
readyList.add( fn );
return this;
},
eq: function( i ) {
i = +i;
return i === -1 ?
this.slice( i ) :
this.slice( i, i + 1 );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
slice: function() {
return this.pushStack( slice.apply( this, arguments ),
"slice", slice.call(arguments).join(",") );
},
map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},
end: function() {
return this.prevObject || this.constructor(null);
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: [].sort,
splice: [].splice
};
no3: 进入append入口
jQuery.fn.extend({text: function( text ) {
if ( jQuery.isFunction(text) ) {
return this.each(function(i) {
var self = jQuery( this );
self.text( text.call(this, i, self.text()) );
});
}
if ( typeof text !== "object" && text !== undefined ) {
return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
}
return jQuery.text( this );
},
wrapAll: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each(function(i) {
jQuery(this).wrapAll( html.call(this, i) );
});
}
if ( this[0] ) {
// The elements to wrap the target around
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
if ( this[0].parentNode ) {
wrap.insertBefore( this[0] );
}
wrap.map(function() {
var elem = this;
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
elem = elem.firstChild;
}
return elem;
}).append( this );
}
return this;
},
wrapInner: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each(function(i) {
jQuery(this).wrapInner( html.call(this, i) );
});
}
return this.each(function() {
var self = jQuery( this ),
contents = self.contents();
if ( contents.length ) {
contents.wrapAll( html );
} else {
self.append( html );
}
});
},
wrap: function( html ) {
var isFunction = jQuery.isFunction( html );
return this.each(function(i) {
jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
});
},
unwrap: function() {
return this.parent().each(function() {
if ( !jQuery.nodeName( this, "body" ) ) {
jQuery( this ).replaceWith( this.childNodes );
}
}).end();
},
append: function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 ) {this.appendChild( elem );
}
});
},
prepend: function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 ) {
this.insertBefore( elem, this.firstChild );
}
});
},
before: function() {
if ( this[0] && this[0].parentNode ) {
return this.domManip(arguments, false, function( elem ) {
this.parentNode.insertBefore( elem, this );
});
} else if ( arguments.length ) {
var set = jQuery.clean( arguments );
set.push.apply( set, this.toArray() );
return this.pushStack( set, "before", arguments );
}
},
after: function() {
if ( this[0] && this[0].parentNode ) {
return this.domManip(arguments, false, function( elem ) {
this.parentNode.insertBefore( elem, this.nextSibling );
});
} else if ( arguments.length ) {
var set = this.pushStack( this, "after", arguments );
set.push.apply( set, jQuery.clean(arguments) );
return set;
}
},
// keepData is for internal use only--do not document
remove: function( selector, keepData ) {
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
if ( !keepData && elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName("*") );
jQuery.cleanData( [ elem ] );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
}
return this;
},
empty: function() {
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
// Remove element nodes and prevent memory leaks
if ( elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName("*") );
}
// Remove any remaining nodes
while ( elem.firstChild ) {
elem.removeChild( elem.firstChild );
}
}
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 );
});
},
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery( this );
self.html( value.call(this, i, self.html()) );
});
} else {
this.empty().append( value );
}
return this;
},
replaceWith: function( value ) {
if ( this[0] && this[0].parentNode ) {
// Make sure that the elements are removed from the DOM before they are inserted
// this can help fix replacing a parent with child elements
if ( jQuery.isFunction( value ) ) {
return this.each(function(i) {
var self = jQuery(this), old = self.html();
self.replaceWith( value.call( this, i, old ) );
});
}
if ( typeof value !== "string" ) {
value = jQuery( value ).detach();
}
return this.each(function() {
var next = this.nextSibling,
parent = this.parentNode;
jQuery( this ).remove();
if ( next ) {
jQuery(next).before( value );
} else {
jQuery(parent).append( value );
}
});
} else {
return this.length ?
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
this;
}
},
detach: function( selector ) {
return this.remove( selector, true );
},
domManip: function( args, table, callback ) {
var results, first, fragment, parent,
value = args[0],
scripts = [];
// We can't cloneNode fragments that contain checked, in WebKit
if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
return this.each(function() {
jQuery(this).domManip( args, table, callback, true );
});
}
if ( jQuery.isFunction(value) ) {
return this.each(function(i) {
var self = jQuery(this);
args[0] = value.call(this, i, table ? self.html() : undefined);
self.domManip( args, table, callback );
});
}
if ( this[0] ) {
parent = value && value.parentNode;
// If we're in a fragment, just use that instead of building a new one
if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
results = { fragment: parent };
} else {
results = jQuery.buildFragment( args, this, scripts ); //构造一个新实例
}
fragment = results.fragment;
if ( fragment.childNodes.length === 1 ) {
first = fragment = fragment.firstChild;
} else {
first = fragment.firstChild;
}
if ( first ) {
table = table && jQuery.nodeName( first, "tr" );
for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
callback.call(
table ?
root(this[i], first) :
this[i],
// Make sure that we do not leak memory by inadvertently discarding
// the original fragment (which might have attached data) instead of
// using it; in addition, use the original fragment object for the last
// item instead of first because it can end up being emptied incorrectly
// in certain situations (Bug #8070).
// Fragments from the fragment cache must always be cloned and never used
// in place.
results.cacheable || ( l > 1 && i < lastIndex ) ?
jQuery.clone( fragment, true, true ) :
fragment
);
}
}
if ( scripts.length ) {
jQuery.each( scripts, evalScript );
}
}
return this;
}
});
//buildFragment 方法
jQuery.buildFragment = function( args, nodes, scripts ) {
var fragment, cacheable, cacheresults, doc,
first = args[ 0 ];
// nodes may contain either an explicit document object,
// a jQuery collection or context object.
// If nodes[0] contains a valid object to assign to doc
if ( nodes && nodes[0] ) {
doc = nodes[0].ownerDocument || nodes[0];
}
// Ensure that an attr object doesn't incorrectly stand in as a document object
// Chrome and Firefox seem to allow this to occur and will throw exception
// Fixes #8950
if ( !doc.createDocumentFragment ) {
doc = document;
}
// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
// Cloning options loses the selected state, so don't cache them
// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
first.charAt(0) === "<" && !rnocache.test( first ) &&
(jQuery.support.checkClone || !rchecked.test( first )) &&
(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
cacheable = true;
cacheresults = jQuery.fragments[ first ];
if ( cacheresults && cacheresults !== 1 ) {
fragment = cacheresults;
}
}
if ( !fragment ) {
fragment = doc.createDocumentFragment();
jQuery.clean( args, doc, fragment, scripts );
}
if ( cacheable ) {
jQuery.fragments[ first ] = cacheresults ? fragment : 1;
}
return { fragment: fragment, cacheable: cacheable };
};
相关推荐
在本篇《jquery 源码初探,一步步实现自己的jquery(四)》中,...每一步都需要仔细研究jQuery源码,理解其背后的逻辑,并尝试用更简洁的方式实现。这样,即使无法完全复制jQuery的所有特性,也能收获宝贵的实践经验。
《jQuery源码分析》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM操作、事件处理、动画制作以及Ajax交互。深入理解其源码对于提升JavaScript编程技能和优化前端性能至关重要。本文将从核心概念、设计...
《jQuery源码深度解析》 jQuery,作为一款广泛使用的JavaScript库,因其简洁的API和强大的功能,深受开发者喜爱。本文将深入探讨jQuery 1.2.6版本的源码,结合其中的中文注释,帮助读者理解其内部机制,提升...
总结,jQuery源码的深度探索是一次宝贵的编程之旅,它让我们看到了一个优秀JavaScript库的设计思想和实现技巧。无论你是初学者还是经验丰富的开发者,深入理解jQuery,都将对你的职业生涯产生深远影响。
源码通常包含书中示例代码,是学习和理解jQuery功能及其实现方式的重要辅助资料。在这里,我们将深入探讨jQuery库的核心概念、主要功能以及如何通过源码来加深理解。 jQuery是一个强大的JavaScript库,它简化了HTML...
同时,jQuery提供了一系列方法,如`$(selector).html()`, `$(selector).append()`等,用于操作DOM元素的内容和结构。 2. **事件处理**:jQuery封装了事件处理函数,如`.on()`, `.off()`, `.trigger()`等,使得事件...
2. **DOM 操作(DOM Manipulation)**:jQuery 提供了一系列方法用于创建、修改和操作DOM元素,如 `append()` 在元素末尾添加内容,`prepend()` 在元素开头添加内容,`html()` 和 `text()` 用于设置或获取元素的HTML...
《Head First jQuery源码》是一本深入解析jQuery库的书籍,其内容主要涵盖了jQuery的核心功能、设计理念以及实现机制。jQuery是JavaScript的一个库,它极大地简化了网页中的DOM操作、事件处理、动画效果以及Ajax交互...
### JQuery源码的奥秘逐行分析视频教程 #### JQuery简介 JQuery 是一款轻量级的 JavaScript 库,它极大地简化了 HTML 文档遍历、事件处理、动画以及 Ajax 交互等操作。JQuery 提供了一个简洁且强大的 API 接口,...
3. **DOM操作(DOM Manipulation)**:jQuery提供了一系列方便的DOM操作方法,如`append()`用于在元素内部追加内容,`remove()`用于删除元素,`clone()`用于复制元素等。 4. **事件处理(Events)**:jQuery简化了...
《jQuery源码分析详解》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了网页的DOM操作、事件处理、动画制作以及Ajax交互。深入理解jQuery的源码,不仅可以提升我们的编程技巧,更能帮助我们优化代码,提高...
《锋利的jQuery源码》是一本专注于深入解析jQuery库源码的专业书籍,旨在帮助开发者理解并掌握jQuery的核心原理和实现机制。jQuery是JavaScript库中的一个里程碑,它极大地简化了DOM操作、事件处理、动画效果以及...
在学习过程中,你可以尝试解决实际问题,比如实现图片轮播、表单验证、动态加载数据等,以巩固 jQuery 的应用。同时,不断探索和学习最新的前端技术,如 Vue.js, React.js 或 Angular.js,将 jQuery 的知识融入到...
2. **DOM操作的实现**: jQuery源码中的DOM操作都是通过JavaScript原生方法实现的,如`appendChild()`和`removeChild()`,但通过封装和优化,提高了跨浏览器的兼容性和性能。 3. **事件委托**: jQuery的事件处理机制...
《jQuery源码解析》 jQuery,作为一款广泛应用于前端开发的JavaScript库,因其简洁的API和强大的功能,深受开发者喜爱。本文将深入探讨jQuery 1.12版本的源码,帮助读者理解其核心机制,提升JavaScript技术能力。 ...
《jQuery源码详细分析中文注释》是一份深入解析jQuery库源码的宝贵资源,它为开发者提供了理解这个广泛使用的JavaScript库内部工作机制的机会。jQuery以其简洁的API和强大的功能深受前端开发者的喜爱,但其背后的...
1. **DOM操作**:jQuery提供了一系列方便的函数来操作DOM元素,如`$("#id")`用于选取指定ID的元素,`.find()`用于查找子元素,`.append()`和`.prepend()`用于在元素内部添加内容。 2. **事件处理**:jQuery简化了...
在这篇文章中,我们将深入探讨jQuery的核心概念、常用方法和如何通过实例源码进行学习。 首先,jQuery的核心概念在于选择器。jQuery的选择器基于CSS,允许开发者快速准确地选取页面中的元素。例如,“#id”选择器...
韩顺平老师的jQuery源码讲解课程,为我们揭示了这个强大库背后的实现原理,帮助我们深入理解JavaScript编程。 首先,jQuery的核心是选择器(Selectors),它实现了类似CSS的选择语法,如$("#id")和$(".class")。...
本资源“基于jQuery实现的et大屏展示源码”提供了使用jQuery技术实现这类效果的具体实践。jQuery作为一个流行的JavaScript库,简化了DOM操作、事件处理、动画效果以及Ajax交互,使得开发者能够更高效地构建动态网页...