`
luozhonghua2014
  • 浏览: 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的所有特性,也能收获宝贵的实践经验。

    Jquery源码分析 源码

    《jQuery源码分析》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM操作、事件处理、动画制作以及Ajax交互。深入理解其源码对于提升JavaScript编程技能和优化前端性能至关重要。本文将从核心概念、设计...

    JQuery源码详细中文注释_Jquery源码分析_

    《jQuery源码深度解析》 jQuery,作为一款广泛使用的JavaScript库,因其简洁的API和强大的功能,深受开发者喜爱。本文将深入探讨jQuery 1.2.6版本的源码,结合其中的中文注释,帮助读者理解其内部机制,提升...

    jquery源码好不容易找到的与大家分享

    总结,jQuery源码的深度探索是一次宝贵的编程之旅,它让我们看到了一个优秀JavaScript库的设计思想和实现技巧。无论你是初学者还是经验丰富的开发者,深入理解jQuery,都将对你的职业生涯产生深远影响。

    Head First jQuery源码

    源码通常包含书中示例代码,是学习和理解jQuery功能及其实现方式的重要辅助资料。在这里,我们将深入探讨jQuery库的核心概念、主要功能以及如何通过源码来加深理解。 jQuery是一个强大的JavaScript库,它简化了HTML...

    jquery源码框架解读

    同时,jQuery提供了一系列方法,如`$(selector).html()`, `$(selector).append()`等,用于操作DOM元素的内容和结构。 2. **事件处理**:jQuery封装了事件处理函数,如`.on()`, `.off()`, `.trigger()`等,使得事件...

    jquery api, jquery ui api, jquery源码分析

    2. **DOM 操作(DOM Manipulation)**:jQuery 提供了一系列方法用于创建、修改和操作DOM元素,如 `append()` 在元素末尾添加内容,`prepend()` 在元素开头添加内容,`html()` 和 `text()` 用于设置或获取元素的HTML...

    Head First jquery源码

    《Head First jQuery源码》是一本深入解析jQuery库的书籍,其内容主要涵盖了jQuery的核心功能、设计理念以及实现机制。jQuery是JavaScript的一个库,它极大地简化了网页中的DOM操作、事件处理、动画效果以及Ajax交互...

    JQuery源码的奥秘逐行分析视频教程

    ### JQuery源码的奥秘逐行分析视频教程 #### JQuery简介 JQuery 是一款轻量级的 JavaScript 库,它极大地简化了 HTML 文档遍历、事件处理、动画以及 Ajax 交互等操作。JQuery 提供了一个简洁且强大的 API 接口,...

    jquery源码

    3. **DOM操作(DOM Manipulation)**:jQuery提供了一系列方便的DOM操作方法,如`append()`用于在元素内部追加内容,`remove()`用于删除元素,`clone()`用于复制元素等。 4. **事件处理(Events)**:jQuery简化了...

    jquery 源码分析

    《jQuery源码分析详解》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了网页的DOM操作、事件处理、动画制作以及Ajax交互。深入理解jQuery的源码,不仅可以提升我们的编程技巧,更能帮助我们优化代码,提高...

    锋利的jQuery 源码

    《锋利的jQuery源码》是一本专注于深入解析jQuery库源码的专业书籍,旨在帮助开发者理解并掌握jQuery的核心原理和实现机制。jQuery是JavaScript库中的一个里程碑,它极大地简化了DOM操作、事件处理、动画效果以及...

    jQuery 源码+实例+注释

    在学习过程中,你可以尝试解决实际问题,比如实现图片轮播、表单验证、动态加载数据等,以巩固 jQuery 的应用。同时,不断探索和学习最新的前端技术,如 Vue.js, React.js 或 Angular.js,将 jQuery 的知识融入到...

    jQuery 源码 文档 插件 集合

    2. **DOM操作的实现**: jQuery源码中的DOM操作都是通过JavaScript原生方法实现的,如`appendChild()`和`removeChild()`,但通过封装和优化,提高了跨浏览器的兼容性和性能。 3. **事件委托**: jQuery的事件处理机制...

    jQuery源码

    《jQuery源码解析》 jQuery,作为一款广泛应用于前端开发的JavaScript库,因其简洁的API和强大的功能,深受开发者喜爱。本文将深入探讨jQuery 1.12版本的源码,帮助读者理解其核心机制,提升JavaScript技术能力。 ...

    jQuery源码详细分析中文注释

    《jQuery源码详细分析中文注释》是一份深入解析jQuery库源码的宝贵资源,它为开发者提供了理解这个广泛使用的JavaScript库内部工作机制的机会。jQuery以其简洁的API和强大的功能深受前端开发者的喜爱,但其背后的...

    50个jquery例子源码

    1. **DOM操作**:jQuery提供了一系列方便的函数来操作DOM元素,如`$("#id")`用于选取指定ID的元素,`.find()`用于查找子元素,`.append()`和`.prepend()`用于在元素内部添加内容。 2. **事件处理**:jQuery简化了...

    锋利的jquery实例源码

    在这篇文章中,我们将深入探讨jQuery的核心概念、常用方法和如何通过实例源码进行学习。 首先,jQuery的核心概念在于选择器。jQuery的选择器基于CSS,允许开发者快速准确地选取页面中的元素。例如,“#id”选择器...

    韩顺平 jquery 源码 传智播客

    韩顺平老师的jQuery源码讲解课程,为我们揭示了这个强大库背后的实现原理,帮助我们深入理解JavaScript编程。 首先,jQuery的核心是选择器(Selectors),它实现了类似CSS的选择语法,如$("#id")和$(".class")。...

    基于jquery实现的et大屏展示源码_大屏展示_前端页面

    本资源“基于jQuery实现的et大屏展示源码”提供了使用jQuery技术实现这类效果的具体实践。jQuery作为一个流行的JavaScript库,简化了DOM操作、事件处理、动画效果以及Ajax交互,使得开发者能够更高效地构建动态网页...

Global site tag (gtag.js) - Google Analytics