jQuery源码-dom操作之jQuery.fn.html
写在前面
前面陆陆续续写了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树渲染好之前 ...
随机推荐
- springMVC-数据的格式化
1.配置annotation-driven <mvc:annotation-driven ></mvc:annotation-driven> 2.在实体类上加上@NumberF ...
- 【bzoj2152】 聪聪可可
http://www.lydsy.com/JudgeOnline/problem.php?id=2152 (题目链接) 题意 给出一棵n个节点的带权树,求有多少点对的距离是3的倍数. solution ...
- Linq集合
摘要:微软在.NET 3.5中推出了LINQ,现在各种LINQ Provider满天飞,TerryLee在老外站点上收集了一份LINQ Provider列表 微软在.NET 3.5中推出了LINQ,现 ...
- CCTray配置如何添加远程服务器
前提: Windows防火墙必须开通的TCP端口 或者直接把防火墙关闭(不建议) 或者直接在防火墙规则增加CCNET的服务进去 总者,只要确保能telnet ip 21234能通即可 建议全部软件都装 ...
- NuGet多个项目依赖的公共组件如何打包
会有这样一种情况:在同一个解决方案下面,类库A是独立的,类库B是依赖于类库A的:类似这样: 所以在使用类库B时必须引入类库A的东西,这时如果作为nuget包打包发布,有如下的解决思路: 1.在整个解决 ...
- NAnt0.92版本首次在windows 8.1的机子上运行报错的问题解决
在官网上下载的0.92版本,各方面都配置好之后,用命令行运行,却提示报错,如下: 具体的错误提示文字是这样的: 获取ConfigurationFileLocation异常. System.Securi ...
- Git: 生成ssh公钥
生成 SSH 公钥 大多数 Git 服务器都会选择使用 SSH 公钥来进行授权.系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个.生成公钥的过程在所有操作系统上都差不多. 首先先确认一 ...
- [iOS 图像处理相关]
//使用CGImage获取并修改图片像素 #define Mask8(x) ( (x) & 0xFF ) #define R(x) ( Mask8(x) ) #define G(x) ( Ma ...
- Fluent interface
In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is an ...
- Android中的Binder机制的简要理解
转载自:http://www.linuxidc.com/Linux/2012-07/66195.htm http://blog.csdn.net/sunxingzhesunjinbiao/articl ...