写在前面
前面陆陆续续写了jQuery源码的一些分析,尽可能地想要cover里面的源码细节,结果导致进度有些缓慢。jQuery的源码本来就比较晦涩,里面还有很多为了解决兼容问题很引入的神代码,如果不google的话压根不知道那一段段代码为什么会存在于人世。
于是就一直在重复坐着这么件事情,到处谷歌或者请教别人,这段兼容代码是为解决神马问题引入的。好不容易把所有的源码细节搞清楚,喝着咖啡对着电脑欣赏自己的劳动成果,内心却闪过一丝奇怪的感觉:我花了这么长的时间究竟做了什么?就为了搞清楚这段常理无法解释的代码?而在这之前已经有无数仁人志士在这上面浪费了自己多少宝贵的时间。
当然,学习jQuery源码对于我这种老菜鸟还是很有助益的,只不过需要换种方式,不再去抠一些无谓的细节了,有些比较难理解的东西就直接扔出来看下园里的朋友们帮忙解答下了。社会化写作似乎是更好的方式,之前也想过把系列文章扔github让别人来帮忙完善,不过显然对于大部分人来说这种方式成本还是太高,而自己写的东西暂时也没有说让人家去fork然后pull request的价值,就作罢了。
技术无关的内容就此打住,还是老老实实开始我的源码分析。里面标疑惑的地方,是还没来得及去抠的细节(一般就是一些正则神马的),围观的群众如果能够帮忙解答下那是真真的好~~
简单例子
jQuery.fn.html()同样属于使用频率比较高的接口,从它的接口文档http://api.jquery.com/html/,可知有如下几种用法,假设有如下HTML片段
<div id="casper">
<span>name:</span>
<span>casper</span>
</div>
读取:$(selector).html()
运行下面代码
console.log( $('#casper').html() );
输出:
<span>name:</span>
<span>casper</span>
设置一:$(selector).html(value)
还是上面的HTML,运行下面脚本
$('#casper').html('<p>大家好,我是第一段文本</p><p>大家好,我是第二段文本</p>');
原本的HTML变成
<div id="casper"><p>大家好,我是第一段文本</p><p>大家好,我是第二段文本</p></div>
设置二:$(selector).html(callback)
在上面例子中,HTML变成如下
<div id="casper"><p>大家好,我是第一段文本</p><p>大家好,我是第二段文本</p></div>
运行如下代码,参数 index、html 分别代码什么,见下面输出即可,不赘述
$('#casper p').html(function(index, html){
return index + '、原本的内容:'+ html;
});
结果原来的HTML变成(为方便查看进行了适当格式化)
<div id="casper">
<p>0、原本的内容:大家好,我是第一段文本</p>
<p>1、原本的内容:大家好,我是第二段文本</p>
</div>
源码分析
下面湿jQuery.fn.html 的源码,就直接贴上来了,一点都不意外,又见到了全知全能的jQuery.access方法。。。这里我们先不立即展开,下文慢慢分析
html: function( value ) {
return jQuery.access( this, function( value ) {
var elem = this[0] || {},
i = 0,
l = this.length; if ( value === undefined ) {
return elem.nodeType === 1 ?
elem.innerHTML.replace( rinlinejQuery, "" ) :
undefined;
} // See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1></$2>" ); try {
for (; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if ( elem.nodeType === 1 ) {
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 );
}
jQuery.fn.html源码
把传入jQuery.access的会掉方法的方法体去掉,我们看到如下代码,就是调用了下jQuery.access而已(这里我们还不知道jQuery.access那噩梦般的参数究竟是干嘛的):
html: function( value ) {
return jQuery.access( this, function( value ) { // 先隐藏掉方法体内的细节 }, null, value, arguments.length );
},
实在不知道如何下手分析jQuery.access,就直接跳过jQuery.access运行的内部细节,给出各种情况下的运行分支
源码分析之:fn被调用的各种情况
假设在jQuery.fn.html方法中,第二个传入的回调方法为fn
读取:$(selector).html()
html: function( value ) {
return fn.call(this);
},
设置一:$(selector).html(value)
html: function( value ) {
fn.call( this, value );
return this;
},
设置二:$(selector).html(callback)
这里可能比较费解一点,得结合设置一的代码来看(其实结合了业不容易看懂),可以看到,内部比较曲折,最终将$(selector).html(callback)转成了$(selector).html(value)来实现,这种转换手法在jQuery源码里很常见。
html: function( callback ) {
var elems = this,
i = 0,
length = elems.length; var bulk = fn;
// elem为dom元素,value为该dom元素最初的innerHTML
fn = function( elem, value ) {
return bulk.call( jQuery( elem ), value );
};
for ( ; i < length; i++ ) {
// 第一步:fn( elems[i], key ) ) 返回elem[i]的innerHTML,相当于 $(elem[i]).html()
// 第二步:callback.call( elems[i], i, fn( elems[i], key ) ),就是将 i、$(elem[i]).html()当参数传给 callback
// 第三步:fn( elems[i], XXXX ) 到了这一步,其实就是 $(elem[i]).html(value)的等价形式了,因为第三步中已经返回了一段html文本
fn( elems[i], callback.call( elems[i], i, fn( elems[i], key ) ) );
} return this;
}
源码分析之:fn各种情况下内部的分支逻辑
接下来到大头,上面说的fn的源码了,下面列出各种情况下,fn内部的处理逻辑
读取:$(selector).html()
fn里面的处理逻辑,很简单,将$(selector)选中的第一个dom元素的innerHTML属性返回。
疑问:rinlinejQuery这个正则是干嘛?为什么还要将elem.innerHTML先替换一下再返回?
var elem = this[0] || {}, // this为选中的jQuery对象
i = 0,
l = this.length; if ( value === undefined ) {
return elem.nodeType === 1 ?
elem.innerHTML.replace( rinlinejQuery, "" ) :
undefined;
}
设置一:$(selector).html(value)
代码也不算复杂,就是遍历下$(selector)选中的元素,将它们的innerHTML分别设置成value。这里麻烦点在于,value存在,还得符合一堆条件才能走进这个if,原谅我偷懒了
疑问:
!rnoInnerhtml.test( value ):判断神马的
( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ):判断神马的
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ):判断神马的
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ]:判断神马的
value = value.replace( rxhtmlTag, "<$1></$2>" ); 作用是神马
// See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1></$2>" ); try {
for (; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
}
} elem = 0; // If using innerHTML throws an exception, use the fallback method
} catch(e) {}
}
设置二:$(selector).html(callback)
这里直接略过,因为fn内部的逻辑是跟$(selector).html(value)一样的
写在后面
本文有些偷懒,凑合着看吧。。里面提到的疑惑,如果能够帮忙解答下就更好了。。。
jQuery源码-dom操作之jQuery.fn.html的更多相关文章
-
jQuery源码-dom操作之jQuery.fn.text
写在前面 jQuery.fn.text在jQuery是个使用频率比较高的接口,它的作用无非是设置/获取dom节点的内容文本,下文会通过几个简单的例子来说明.text()接口的使用,以及最后会对源码进行 ...
-
jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究
终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...
-
jQuery源码中的“new jQuery.fn.init()”什么意思?
所有文章搬运自我的个人主页:sheilasun.me 引子 最近打算试试看看jQuery的源码,刚开个头就卡住了.无论如何都理解不了jQuery源码入口部分中的 return new jQuery.f ...
-
jquery源码 DOM加载
jQuery版本:2.0.3 DOM加载有关的扩展 isReady:DOM是否加载完(内部使用) readyWait:等待多少文件的计数器(内部使用) holdReady():推迟DOM触发 read ...
-
jQuery源码笔记(一):jQuery的整体结构
jQuery 是一个非常优秀的 JS 库,与 Prototype,YUI,Mootools 等众多的 Js 类库相比,它剑走偏锋,从 web 开发的实用角度出发,抛除了其它 Lib 中一些中看但不实用 ...
-
jQuery源码逐行分析学习01(jQuery的框架结构简化)
最近在学习jQuery源码,在此,特别做一个分享,把所涉及的内容都记录下来,其中有不妥之处还望大家指出,我会及时改正.望各位大神不吝赐教!同时,这也是我的第一篇前端技术博客,对博客编写还不是很熟悉,美 ...
-
jQuery 源码解析一:jQuery 类库整体架构设计解析
如果是做 web 的话,相信都要对 Dom 进行增删查改,那大家都或多或少接触到过 jQuery 类库,其最大特色就是强大的选择器,让开发者脱离原生 JS 一大堆 getElementById.get ...
-
[转] jQuery源码分析-如何做jQuery源码分析
jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...
-
jQuery源码dom ready分析
一.前言 在平时开发web项目时,我们使用jquery框架时,可能经常这样来使用$(document).ready(fn),$(function(){}),这样使用的原因是在浏览器把DOM树渲染好之前 ...
随机推荐
-
oradebug/strace/pstack等分析数据库性能问题系列一
对于性能问题或者一些比较奇怪妖异的问题,有很多点可以着手去分析. 准备写一个系列关于用ash/dba_hist_active_sess_history,用oradebug,用linux命令strace ...
-
Bootstrap之表格checkbox复选框全选
效果图: HTML中无需添加额外的一列来表示复选框,而是由JS完成,所以正常的表格布局就行了: <table class="table table-bordered table-hov ...
-
Java NIO非阻塞理论学习
Java NIO和阻塞IO的区别: 阻塞I/O在调用InputStream.read()方法时是阻塞的,它会一直等到数据到来时(或超时)才会返回:同样,在调用ServerSocket.accept() ...
-
Install Google Pinyin on Ubuntu 14.04
Install Google Pinyin on Ubuntu 14.04 I've been spending more and more time on Ubuntu and I'm not us ...
-
DbInitializer.cs初始化过程中context.entityName.Add()遇到的类型不匹配错误
用Asp.Net Core+EF Core建立一个测试项目过程中,使用DbInitializaer.cs进行数据库表的初始化工作,当项目测试运行时执行到context.实体名.Add()时,提示错误信 ...
-
java的各个队列之间的联系和区别是什么
java的各个并发队列之间的联系和区别 java.util.concurrent是在并发编程中很常用的实用工具类 ArrayBlockingQueue, DelayQueue, LinkedBlock ...
-
java Script 中的keyCode 和charCode
其实很长一段时间,我都没有完全弄明白keyCode 和charCode ,自己也认真看过,但是就是理解不透彻,为了防止以后再出现混乱,写篇博客记录一下吧! 首先 在不同的浏览器中,他们有不同的说法哦 ...
-
linux监控命令全覆盖(图文说明)
1.1 top 1.1.1 命令说明 Top 命令能够实时监控系统的运行状态,并且可以按照cpu.内存和执行时间进行排序 1.1.2 参数说明 命令行启动参数: 用法: top -hv | -bcis ...
-
SQL点滴6—“微软不认识闰年2月29日”&;字符";N";的作用
原文:SQL点滴6-"微软不认识闰年2月29日"&字符"N"的作用 http://www.cnbeta.com/articles/50580.htm这个 ...
-
React之key详解
一个例子 有这样的一个场景如下图所示,有一组动态数量的input,可以增加和删除和重新排序,数组元素生成的组件用index作为key的值,例如下图生成的ui展示: 上面例子中的input组件渲染的代码 ...