append: function() { //传入arguments对象,true为要对表格进行特殊处理,回调函数 return this.domManip(arguments, true, function(elem){ if (this.nodeType == 1) this.appendChild( elem ); }); }, domManip: function( args, table, callback ) { if ( this[0] ) {//如果存在元素节点 var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(), //注意这里是传入三个参数 scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ), first = fragment.firstChild;
if ( first ) for ( var i = 0, l = this.length; i callback.call( root(this[i], first), this.length > 1 || i > 0 ? fragment.cloneNode(true) : fragment );
if ( scripts ) jQuery.each( scripts, evalScript ); }
// !context.createElement fails in IE with an error but returns typeof 'object' if ( typeof context.createElement === "undefined" ) //确保context为文档对象 context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
// If a single string is passed in and it's a single tag // just do a createElement and skip the rest //如果文档对象里面只有一个标签,如
//我们大概可能是在外面这样调用它$(this).append("
") //这时就直接把它里面的元素名取出来,用document.createElement("div")创建后放进数组返回 if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { var match = /^$/.exec(elems[0]); if ( match ) return [ context.createElement( match[1] ) ]; } //利用一个div的innerHTML创建众节点 var ret = [], scripts = [], div = context.createElement("div"); //如果我们是在外面这样添加$(this).append("
表格1
","
表格1
","
表格1
") //jQuery.each按它的第四种支分方式(没有参数,有length)遍历aguments对象,callback.call( value, i, value ) jQuery.each(elems, function(i, elem){//i为索引,elem为arguments对象里的元素 if ( typeof elem === "number" ) elem += '';
if ( !elem ) return;
// Convert html string into DOM nodes if ( typeof elem === "string" ) { // Fix "XHTML"-style tags in all browsers elem = elem.replace(/(]*?)\/>/g, function(all, front, tag){ return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? all : front + ">" + tag + ">"; });
// Trim whitespace, otherwise indexOf won't work as expected var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
var wrap = // option or optgroup !tags.indexOf(" [ 1, "" ] ||
!tags.indexOf(" [ 1, "" ] ||
tags.match(/^ [ 1, "
", "
" ] ||
!tags.indexOf("
[ 2, "
", "
" ] ||
// matched above (!tags.indexOf("
[ 3, "
", "
" ] ||
!tags.indexOf("
[ 2, "
", "
" ] ||
// IE can't serialize and <script> tags normally <BR> !jQuery.support.htmlSerialize &&//用于创建link元素 <BR> [ 1, "div<div>", "" ] || <br><br> [ 0, "", "" ]; <br><br> // Go to html and back, then peel off extra wrappers <BR> div.innerHTML = wrap[1] + elem + wrap[2];//比如"<table><tbody><tr>" +<td>表格1</script>
+""
// Move to the right depth while ( wrap[0]-- ) div = div.lastChild;
insert : function(el,stuff,where){ //定义两个全局的东西,提供内部方法调用 var doc = el.ownerDocument || dom.doc, fragment = doc.createDocumentFragment(); if(stuff.version){//如果是dom对象,则把它里面的元素节点移到文档碎片中 stuff.forEach(function(el){ fragment.appendChild(el); }) stuff = fragment; } //供火狐与IE部分元素调用 dom._insertAdjacentElement = function(el,node,where){ switch (where){ case 'beforeBegin': el.parentNode.insertBefore(node,el) break; case 'afterBegin': el.insertBefore(node,el.firstChild); break; case 'beforeEnd': el.appendChild(node); break; case 'afterEnd': if (el.nextSibling) el.parentNode.insertBefore(node,el.nextSibling); else el.parentNode.appendChild(node); break; } }; //供火狐调用 dom._insertAdjacentHTML = function(el,htmlStr,where){ var range = doc.createRange(); switch (where) { case "beforeBegin"://before range.setStartBefore(el); break; case "afterBegin"://after range.selectNodeContents(el); range.collapse(true); break; case "beforeEnd"://append range.selectNodeContents(el); range.collapse(false); break; case "afterEnd"://prepend range.setStartAfter(el); break; } var parsedHTML = range.createContextualFragment(htmlStr); dom._insertAdjacentElement(el,parsedHTML,where); }; //以下元素的innerHTML在IE中是只读的,调用insertAdjacentElement进行插入就会出错 // col, colgroup, frameset, html, head, style, title,table, tbody, tfoot, thead, 与tr; dom._insertAdjacentIEFix = function(el,htmlStr,where){ var parsedHTML = dom.parseHTML(htmlStr,fragment); dom._insertAdjacentElement(el,parsedHTML,where) }; //如果是节点则复制一份 stuff = stuff.nodeType ? stuff.cloneNode(true) : stuff; if (el.insertAdjacentHTML) {//ie,chrome,opera,safari都已实现insertAdjactentXXX家族 try{//适合用于opera,safari,chrome与IE el['insertAdjacent'+ (stuff.nodeType ? 'Element':'HTML')](where,stuff); }catch(e){ //IE的某些元素调用insertAdjacentXXX可能出错,因此使用此补丁 dom._insertAdjacentIEFix(el,stuff,where); } }else{ //火狐专用 dom['_insertAdjacent'+ (stuff.nodeType ? 'Element':'HTML')](el,stuff,where); } }
insert方法在实现火狐插入操作中,使用了W3C DOM Range对象的一些罕见方法,具体可到火狐官网查看。下面实现把字符串转换为节点,利用innerHTML这个伟大的方法。Prototype.js称之为_getContentFromAnonymousElement,但有许多问题,dojo称之为_toDom,mootools的Element.Properties.html,jQuery的clean。Ext没有这东西,它只支持传入HTML片断的insertAdjacentHTML方法,不支持传入元素节点的insertAdjacentElement。但有时,我们需要插入文本节点(并不包裹于元素节点之中),这时我们就需要用文档碎片做容器了,insert方法出场了。