欢迎来我的专栏检察系列文章。
上一章谈到了 dom 的几个插进去操纵,虽然插进去的体式格局多种多样,但只要在懂了原生要领等基本上,代码看起来都不是很庞杂。比较有意思的一个函数就是 buildFragment 要领,用来将 html 字符串转换成 dom 碎片。本章来看一下 dom 的别的要领。
html、text 要领
说到 elem 的操纵,就必定要提一下 elem 的范例。NodeType,一个节点的 nodeType
为 1 示意元素节点,为 3 示意 text 笔墨节点,为 9 示意 document,11 示意 documentFragment,就是上一章所说的文档碎片。也许晓得这几个就能够了。
原生的 elem 要领包含 innerHTML,outerHTML,innerText,outerText,然则,在最先本章之前,一定要对这几个要领很常闇练才行。解密jQuery内核 DOM操纵要领(二)html,text,val。
innerHTML 和 outerHTML 一个明显的差别性就是 outer 会把当前 elem 也一同算进去并取得 html 字符串,inner 不会。
innerText 和 outerText 猎取时刻没有明显差别,然则 set 状况下(设置)的时刻,outer 会把当前 elem 也给删掉,运用照样要郑重。
有时刻由于浏览器的兼容问题,能够用 textContent 替换 innerText。
access 函数源码
下面是jQuery.fn.html
和 text 的源码,看了以后一定有话要说:
jQuery.fn.extends( {
html: function( value ) {
return access( this, function( value ) {
... // callback 函数
}, null, value, arguments.length )
}),
text: function( value ) {
return access( this, function( value ) {
...// 回调函数
}, null, value, arguments.length)
})
} );
好吧,我认可,又是一样的套路,先交给 access 函数来处置惩罚,然后 callback 函数,我猜这个时刻 callback 函数一定是采纳 call 体式格局使 this 绑定当前 elem。这个套路素昧平生,对,就是 domManip 函数。
实在 access 前面已引见了过了,不过照样值得来重现引见一下。
像 html、text、css 这些函数的功用,都有一个特性,就是能够带参数,也能够不带参数,先用 access 函数对参数校订,实行回调。
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
len = elems.length,
bulk = key == null;
// key values 多种状况
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
access( elems, fn, i, key[ i ], true, emptyGet, raw );
}
// Sets 状况
} else if ( value !== undefined ) {
chainable = true;
// value 为函数,不晓得这是一种什么状况
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
if ( bulk ) {
// 实行回调
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
// css 走这一步
if ( fn ) {
for ( ; i < len; i++ ) {
fn(
elems[ i ], key, raw ?
value :
value.call( elems[ i ], i, fn( elems[ i ], key ) )
);
}
}
}
// chainable 示意参数长度 0 或 1
if ( chainable ) {
return elems;
}
// Gets
if ( bulk ) {
return fn.call( elems );
}
return len ? fn( elems[ 0 ], key ) : emptyGet;
};
access 中涌现了一种 value 为函数的状况,没有碰到过,暂不晓得什么意思。access 函数基本没有做太大的变化处置惩罚看,看起来也不是很难。(哈哈,找到了,背面 css 操纵的时刻,key 能够为 object)
fn.html 源码
如今就是重要来看这个回调函数了,当前的 this 使指向 jQuery 对象的,并没有指向零丁的 elem 元素,html 一定要举行推断:
jQuery.fn.extends( {
html: function( value ) {
return access( this, function( value ) {
var elem = this[ 0 ] || {},
i = 0,
l = this.length;
// 参数为空的状况,get
if ( value === undefined && elem.nodeType === 1 ) {
return elem.innerHTML;
}
// set 操纵
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
value = jQuery.htmlPrefilter( value );
try {
for ( ; i < l; i++ ) {
elem = this[ i ] || {};
// Remove element nodes and prevent memory leaks
if ( elem.nodeType === 1 ) {
// cleanData 是消灭 dom 绑定 cache 的数据
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
}
}
elem = 0;
// If using innerHTML throws an exception, use the fallback method
} catch ( e ) {}
}
if ( elem ) {
this.empty().append( value );
}
}, null, value, arguments.length );
}
} );
fn.text 源码
下面是 text 源码,关于 html 和 text 在开首已引见了,算是比较基本的 dom 操纵吧,直接来看源码吧:
jQuery.fn.extends( {
text: function( value ) {
return access( this, function( value ) {
// 前面已说了,回调函数里的 this 指向 jQuery 对象
return value === undefined ?
// get
jQuery.text( this ) :
// set
this.empty().each( function() {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
this.textContent = value;
}
} );
}, null, value, arguments.length );
}
} );
先来看看 set 的状况,这里有个 empty 函数,源码在下面,两个功用,先清空 dom 内容,在删除 data cache 中保留的数据。这里没有用 innerText 要领,而是运用 textContent 要领,貌似就 set 来讲,textContent 兼容性更好。
jQuery.fn.extends( {
empty: function() {
var elem,
i = 0;
for ( ; ( elem = this[ i ] ) != null; i++ ) {
if ( elem.nodeType === 1 ) {
// Prevent memory leaks
jQuery.cleanData( getAll( elem, false ) );
// 清空
elem.textContent = "";
}
}
return this;
},
} );
set 的要领晓得了,那末 get 呢?get 起首挪用了 jQuery.text
要领,找了半天赋找到它在那里,本来挪用的是 Sizzle 中的要领:
jQuery.text = Sizzle.getText;
var getText = Sizzle.getText = function( elem ) {
var node,
ret = "",
i = 0,
nodeType = elem.nodeType;
if ( !nodeType ) {
// elem 是一个 dom 数组
while ( (node = elem[i++]) ) {
// 分步来搞
ret += getText( node );
}
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
// innerText usage removed for consistency of new lines (jQuery #11153)
// 依旧运用 textContent 要领
if ( typeof elem.textContent === "string" ) {
return elem.textContent;
} else {
// Traverse its children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
ret += getText( elem );
}
}
// 3 (text)或 4 (4 貌似被移除)直接返回 nodeValue
} else if ( nodeType === 3 || nodeType === 4 ) {
return elem.nodeValue;
}
return ret;
};
总结
我本身在浏览器上面测试,发明 textContent 要领并不会把空白符给删了,而且 jQuery 的 text 要领也没有做过滤,每一个浏览器的剖析也不一样,就可能致使浏览器带来的差别,实际运用的时刻,照样要警惕点好,多长个心眼。
参考
本文在 github 上的源码地点,欢迎来 star。
欢迎来我的博客交换。