一个普通的 Zepto 源码分析(一) - ie 与 form 模块

普通的路人,普通地瞧。分析时使用的是目前最新 1.2.0 版本。

Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以及 event 、 ajax 、 form ,还有一个说是可以支持 IE10 和 WP8 的 ie 模块。

Zepto 基本模块之 ie 模块

由于这个模块比较短小,就是一个对 getComputedStyle() 的封装,而且核心模块也有用到这个函数。那么首先来看看:

;(function(){
// getComputedStyle shouldn't freak out when called
// without a valid element as argument
try {
getComputedStyle(undefined)
} catch(e) {
var nativeGetComputedStyle = getComputedStyle
window.getComputedStyle = function(element, pseudoElement){
try {
return nativeGetComputedStyle(element, pseudoElement)
} catch(e) {
return null
}
}
}
})()

那么我们可以看到,这个模块对原生的 getComputedStyle() 做了一层封装,来屏蔽当传入参数不正确时抛出的异常。比如传入的第一个参数不是一个 Element 节点(继承自 Node 节点接口),而是其他的比如 document 或者是 Text 节点等,都会抛出异常。这里为了插件的正常运行,返回 null 就好了。

其他关于该函数的返回值、 CSS 安全等内容参见 MDN 。

Zepto 基本模块之 form 模块

另一个比较短小的模块,在原型上增加了 serialize()serializeArray()submit() 这 3 个方法。

serializeArray() 会把 form 表单序列化成一个由 namevalue 属性组成的对象的数组。

序列化函数 serialize()

没错,还是先看代码短的:

  $.fn.serialize = function(){
var result = []
this.serializeArray().forEach(function(elm){
result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value))
})
return result.join('&')
}

嗯,非常的简单粗暴,直接把 this.serializeArray() 的结果遍历一遍来进一步序列化成 URL-encoded 的形式,不仅用了两倍空间,还用了两倍时间。至于 encodeURIComponent() 就是很常见的函数了,在 MDN 上有一个对该函数遵循 RFC3986 或 RFC5987 的修补实现。

我认为其实可以抽象出一个基本的遍历函数出来,再在两个序列化函数中传不同的参数或者回调函数来获得不同的输出。

另外,这里没有处理 POST 的数据格式,即把 %20 替换为 + ,我认为 Zepto 这个是错误的实现。所以翻了下 jQuery 的实现,果然(另 Zepto 的 $.param() 有这样的替换,见 ajax 模块):

    serialize: function() {
return jQuery.param( this.serializeArray() );
}

序列化成键值对象数组 serializeArray()

再看看长得丑的:

  $.fn.serializeArray = function() {
var name, type, result = [],
add = function(value) {
// 关注点 3 (可遍历元素的重入)
if (value.forEach) return value.forEach(add)
result.push({ name: name, value: value })
}
// 关注点 1
if (this[0]) $.each(this[0].elements, function(_, field){
type = field.type, name = field.name
// 关注点 2 (过滤无关的表单元素)
if (name && field.nodeName.toLowerCase() != 'fieldset' &&
!field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' &&
((type != 'radio' && type != 'checkbox') || field.checked))
add($(field).val())
})
return result
}

首先是拿到类数组集合对象的第一个元素,这里我猜如果通过 Zepto 查询到多个表单的话,最终序列化的也是第一个。

然后是对元素遍历,注意是 HTML form 元素有 elements 属性,若是一个其他元素比如 div 就直接返回空数组了。感觉可以做个存在判断,这样就不用进入函数了,但多一次判断的开销。

遍历回调中,使用了下划线屏蔽第一个参数,接着筛掉不需序列化的元素。这里把单选和多选也筛了,后面再检查 checked 属性,并不是因为有 option 元素(它是包含在 select 里的),而是像 button 把 type 设置一下就能成为单选或多选,或者其他一些自定义支持 checked 属性的元素的情况。

再看回前面的匿名函数表达式,赋值给了 add 并捕获了 nametypeadd 变量,当传入的值拥有 forEach 就会在其回调中重新调用自己,比如 select 下的值。否则就直接生成一个键值对象压入数组。

提交函数 submit()

最后看看同样代码比较短的:

  $.fn.submit = function(callback) {
// 关注点 1
if (0 in arguments) this.bind('submit', callback)
else if (this.length) {
var event = $.Event('submit')
this.eq(0).trigger(event)
// 关注点 2
if (!event.isDefaultPrevented()) this.get(0).submit()
}
return this
}

这里 0 in arguments 的判断应该是为速度做的优化,判断 in 还是比较快的。至于 bind() 也是常用的事件函数了(但已废弃)。如果没有传入回调函数,则使用 Event 插件在第一个表单上触发一个默认冒泡的 submit 事件,如果事件没有被阻止则调用 HTML 表单的 submit() ,注意区分 eq()get() ,后者是返回 HTML 元素的。

系列相关

一个普通的 Zepto 源码分析(一) - ie 与 form 模块

一个普通的 Zepto 源码分析(二) - ajax 模块

一个普通的 Zepto 源码分析(三) - event 模块

本文基于 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 发布,欢迎引用、转载或演绎,但是必须保留本文的署名 BlackStorm 以及本文链接 http://www.cnblogs.com/BlackStorm/p/Zepto-Analysing-For-IE-And-Form-Module.html ,且未经许可不能用于商业目的。如有疑问或授权协商请 与我联系

一个普通的 Zepto 源码分析(一) - ie 与 form 模块的更多相关文章

  1. 一个普通的 Zepto 源码分析(二) - ajax 模块

    一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...

  2. 一个普通的 Zepto 源码分析(三) - event 模块

    一个普通的 Zepto 源码分析(三) - event 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块, ...

  3. Zepto源码分析(一)核心代码分析

    本文只分析核心的部分代码,并且在这部分代码有删减,但是不影响代码的正常运行. 目录 * 用闭包封装Zepto * 开始处理细节 * 正式处理数据(获取选择器选择的DOM) * 正式处理数据(添加DOM ...

  4. Zepto源码分析(二)奇淫技巧总结

    Zepto源码分析(一)核心代码分析 Zepto源码分析(二)奇淫技巧总结 目录 * 前言 * 短路操作符 * 参数重载(参数个数重载) * 参数重载(参数类型重载) * CSS操作 * 获取属性值的 ...

  5. zepto源码分析系列

    如果你也开发移动端web,如果你也用zepto,应该值得你看看.有问题请留言. Zepto源码分析-架构 Zepto源码分析-zepto(DOM)模块 Zepto源码分析-callbacks模块 Ze ...

  6. jQuery 源码分析(十九) DOM遍历模块详解

    jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装 ...

  7. jQuery 源码分析(二十一) DOM操作模块 删除元素 详解

    本节说一下DOM操作模块里的删除元素模块,该模块用于删除DOM里的某个节点,也可以理解为将该节点从DOM树中卸载掉,如果该节点有绑定事件,我们可以选择保留或删除这些事件,删除元素的接口有如下三个: e ...

  8. jQuery 源码分析(二十) DOM操作模块 插入元素 详解

    jQuery的DOM操作模块封装了DOM模型的insertBefore().appendChild().removeChild().cloneNode().replaceChild()等原生方法.分为 ...

  9. jQuery 源码分析(十二) 数据操作模块 html特性 详解

    jQuery的属性操作模块总共有4个部分,本篇说一下第1个部分:HTML特性部分,html特性部分是对原生方法getAttribute()和setAttribute()的封装,用于修改DOM元素的特性 ...

随机推荐

  1. 【LeetCode】219. Contains Duplicate II

    题目: Given an array of integers and an integer k, find out whether there are two distinct indices i a ...

  2. 【Android Developers Training】 58. 缓存位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【PHP】制作日历

    本期本博主将讲述两种利用PHP制作日历的方法,由于PHP日期函数的便捷性,使得我们制作日历这一过程变得相当简单 问题描述: 1.取到当前日期,并着色显示:2.根据当前日期,判断本月有多少天,一号是周几 ...

  4. Spring事务管理的两种方式

    参考文档: http://www.iteye.com/topic/1123347 http://blog.csdn.net/lcj8/article/details/2835432 PS:好像还是tx ...

  5. usaco 2002 月赛 Chores 题解

    Description Farmer John's family pitches in with the chores during milking, doing all the chores as ...

  6. Watson Explorer Analytical Components 3 - use case scenarios

    The followings are the user case scenarios that WEX can be used for generating value. 1.Customer Ins ...

  7. Unreal Engine 4 Radiant UI 插件入门(三)——从蓝图中调用JS

    不知道大家有没有混淆.这篇教程说的是从蓝图中调用JS的功能(以改变H5内的内容). 在安装了UE4和RadiantUI的前提下学习这篇教程.本篇教程接着上一篇教程,建议请先看上一篇. 第一步:在网页中 ...

  8. EventBus 事件总线之我的理解

    用例:假设公司发布了一个公告 需要通过短信 和 邮件分别2种方式 通知员工 1:首先我们建立领域模型 /// <summary> /// 领域核心基类 /// </summary&g ...

  9. Luogu 1090 合并果子(贪心,优先队列,STL运用)

    Luogu 1090 合并果子(贪心,优先队列,STL运用) Description 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每 ...

  10. anaconda 下多版本Python 安装说明

    网上针对多版本的Python兼容安装的文章逐渐增多,都是大家在实践中总结的经验.本人的安装经过几次的反复实验还是觉得其中一种更为方便. 有人的安装方法是: 1. 先安装一个版本的python(一般先安 ...