前言

我们移动端基本使用zepto了,而我也从一个小白变成稍微靠谱一点的前端了,最近居然经常要改到zepto源码
但是,我对zepto不太熟悉,其实前端水准还是不够,所以便私下偷偷学习下吧,别被发现了

核心方法$()

我们使用这个方法一般有几个用途(我这里只说我自己用到过的),这里根据使用度排个序:

① 选择器/$(selector)

将返回一个包装过的dom集合对象(有很多选择器)

② html字符串/$(domStr)

仍然返回一个包装过的dom对象,他会将字符串初始化为我们的dom结构
PS:新增了一个方法可以直接赋予dom结构属性,我们这里不关注

③ 函数/$(function(){})

我基本没这么用过,他实在文档加载结束后执行

暂时不管这些东西吧。我们这里来一个个看看他们的实现:

 $('div')
//=> all DIV elements on the page
$('#foo')
//=> element with ID "foo" // create element:
$("<p>Hello</p>")
//=> the new P element
// create element with attributes:
$("<p />",
{
text: "Hello",
id: "greeting",
css: { color: 'darkblue' }
})
//=> <p id=greeting style="color:darkblue">Hello</p>
// execute callback when the page is ready:
Zepto(function ($) {
alert('Ready to Zepto!')
})

入口$()

只如初见

首先我们来看看选择器,在zepto代码中有这么一行代码:

 $ = function (selector, context) {
return zepto.init(selector, context)
}

这里其实前面就定义了$这个变量:

var undefined, key, $, classList, emptyArray = [],

这里初始化了$这个变量为一个函数,最后并将这个变量公开化(现在再匿名还是中,外面是访问不到的),他具体是这样干的

 var Zepto = function () {
var zepto = {}, $;
zepto.init = function (selector, context) {
};
$ = function (selector, context) {
return zepto.init(selector, context);
};
$.zepto = zepto;
return $;
};
window.$ = Zepto;

于是我们在页面中使用这样的代码:

 var el = $('#id');
//实际上是
var el = zepto.init('#id');

具体里面的逻辑就是我们的重点,于是我们跟进去慢慢看吧

一查到底

我们详细看看zepto.init这个方法

 zepto.init = function (selector, context) {
if (!selector) return zepto.Z()
else if (isFunction(selector)) return $(document).ready(selector)
else if (zepto.isZ(selector)) return selector
else {
var dom
if (isArray(selector)) dom = compact(selector)
else if (isObject(selector))
dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null
else if (fragmentRE.test(selector))
dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
else if (context !== undefined) return $(context).find(selector)
else dom = zepto.qsa(document, selector)
return zepto.Z(dom, selector)
}
}

第一步,如果选择器selector不存在的话,就调用默认的方法,说白了就是返回一个集合长度为0的包装对象

 //通过给dom设置__proto__属性指向$.fn来达到继承$.fn上所有方法的目的
//ie自然是不支持的,zepto也基本不理睬ie
zepto.Z = function (dom, selector) {
dom = dom || []
dom.__proto__ = $.fn
dom.selector = selector || ''
return dom
}

第二步,处理传入函数情况,如果传入是函数的话就在文档加载结束后执行
第三步,处理传入zepto对象,如果已经是zepto包装对象了就直接返回

 zepto.isZ = function (object) {
return object instanceof zepto.Z
}

第四步,开始了复杂的逻辑计算了,我们这里单独提出来

selector处理

① 数组项

如果对象是一个数组,则去掉其中无意义的数组项

 //清除给定的参数中的null或undefined,注意0==null,'' == null为false
function compact(array) {
return filter.call(array, function (item) {
return item != null
})
}

filter

其中filter是javascript数组的一个新的方法,用以筛选满足条件的数组项

 var arr = [5, "element", 10, "the", true];
var result = arr.filter(
function (value) {
return (typeof value === 'string');
}
);
document.write(result);//Output: element, the

最后返回数组项,我们这里认为其中每个数组项都是一个dom结构

② 传入对象

因为typeof dom也是object,所以zepto这里做了一点扩展

 function isObject(obj) {
return type(obj) == "object"
}

这个代码存在的意义,老夫也不知道了......if里面的代码比较关键:
如果传入的是对象(比如{}),就将selector拷贝到一个对象,如果是dom结构就直接放入数组
这里有两个方法需要注意,一个是extend,一个是isPlainObject

extend

extend用于为对象扩展对象

 function extend(target, source, deep) {
for (key in source)
//如果深度扩展
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
//如果要扩展的数据是对象且target相对应的key不是对象
if (isPlainObject(source[key]) && !isPlainObject(target[key])) target[key] = {}
//如果要扩展的数据是数组且target相对应的key不是数组
if (isArray(source[key]) && !isArray(target[key])) target[key] = []
extend(target[key], source[key], deep)
} else if (source[key] !== undefined) target[key] = source[key]
}

$.extend事实上也是调用的上面的方法,我们这里先不管他

 $.extend = function (target) {
var deep, args = slice.call(arguments, 1)
if (typeof target == 'boolean') { //当第一个参数为boolean类型的值时,表示是否深度扩展
deep = target
target = args.shift() //target取第二个参数
}
//遍历后面的参数,全部扩展到target上
args.forEach(function (arg) {
extend(target, arg, deep)
})
return target
}

isPlainObject

这个方法有所不同,通过字面量定义的对象和new Object的对象返回true,new Object时传参数的返回false(测试对象是否纯粹的对象)

 function isPlainObject(obj) {
return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype
}
$.isPlainObject({})// => true
$.isPlainObject(new Object) // => true
$.isPlainObject(new Date) // => false
$.isPlainObject(window) // => false

至于这个数组到底是不是dom,代码这里先不关注,完了这里也结束了

③ 传入html字符串

如果传入的是html字符串,我们这里就要负责创建dom的工作了,整个这个东西其实比较复杂:

 //HTML代码片断的正则
fragmentRE = /^\s*<(\w+|!)[^>]*>/,

PS:我正则不行,暂时就不尝试去解释这个了

字符串=>dom

 zepto.fragment = function (html, name, properties) {
//将类似<div class="test"/>替换成<div class="test"></div>,算是一种修复吧
if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")
//给name取标签名
if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
//设置容器标签名,如果不是tr,tbody,thead,tfoot,td,th,则容器标签名为div
if (!(name in containers)) name = '*'
var nodes, dom, container = containers[name] //创建容器
container.innerHTML = '' + html //将html代码片断放入容器
//取容器的子节点,这样就直接把字符串转成DOM节点了
dom = $.each(slice.call(container.childNodes), function () {
container.removeChild(this) //逐个删除
})
//如果properties是对象, 则将其当作属性来给添加进来的节点进行设置
if (isPlainObject(properties)) {
nodes = $(dom) //将dom转成zepto对象,为了方便下面调用zepto上的方法
//遍历对象,设置属性
$.each(properties, function (key, value) {
//如果设置的是'val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset',则调用zepto上相对应的方法
if (methodAttributes.indexOf(key) > -1) nodes[key](value)
else nodes.attr(key, value)
})
}
//返回将字符串转成的DOM节点后的数组,比如'<li></li><li></li><li></li>'转成[li,li,li]
return dom
}

这个方法比较高深,各位慢慢消化,我稍后也再去消化下
以上完了后,就返回了创建后的dom结构了......

④ 上下文

如果带有上下文,就得使用上下文查找,没有就在document中查询

 zepto.qsa = function (element, selector) {
var found
return (isDocument(element) && idSelectorRE.test(selector)) ?
((found = element.getElementById(RegExp.$1)) ? [found] : []) :
(element.nodeType !== 1 && element.nodeType !== 9) ? [] :
slice.call(
classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) :
tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) :
element.querySelectorAll(selector)
)
}

这个函数与上面函数一样重要,各位下去消化吧

⑤ 结束

最后的最后便返回我们的包装集合了,这里依旧使用zepto.Z(dom, selector)进行封装

深入zepto.fragment

待续......

深入zepto.qsa

待续......

结语

今天的学习暂时到这里,我们下次继续。

【zepto学习笔记01】核心方法$()的更多相关文章

  1. 【zepto学习笔记01】核心方法$()(补)

    前言 昨天学习了核心$(),有几个遗留问题,我们今天来看看吧 $.each 遍历数组/对象,将每条数据作为callback的上下文,并传入数据以及数据的索引进行处理,如果其中一条数据的处理结果明确返回 ...

  2. Redis:学习笔记-01

    Redis:学习笔记-01 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 1. Redis入门 2.1 ...

  3. 软件测试之loadrunner学习笔记-01事务

    loadrunner学习笔记-01事务<转载至网络> 事务又称为Transaction,事务是一个点为了衡量某个action的性能,需要在开始和结束位置插入一个范围,定义这样一个事务. 作 ...

  4. C++ GUI Qt4学习笔记01

    C++ GUI Qt4学习笔记01   qtc++signalmakefile文档平台 这一章介绍了如何把基本的C++只是与Qt所提供的功能组合起来创建一些简单的图形用户界面应用程序. 引入两个重要概 ...

  5. SaToken学习笔记-01

    SaToken学习笔记-01 SaToken版本为1.18 如果有排版方面的错误,请查看:传送门 springboot集成 根据官网步骤maven导入依赖 <dependency> < ...

  6. PHP 学习笔记 01

    例子: 为什么要学PHP 主观原因: 前段时间在学校处理了毕业的一些事情,回到上海后开始了找工作的旅程.意向工作是WPF开发或者ASP.NET 作为后端的WEB开发. 陆陆续续一直在面试,其中有一家公 ...

  7. vue.js 2.0 官方文档学习笔记 —— 01. vue 介绍

    这是我的vue.js 2.0的学习笔记,采取了将官方文档中的代码集中到一个文件的形式.目的是保存下来,方便自己查阅. !官方文档:https://cn.vuejs.org/v2/guide/ 01. ...

  8. [Golang学习笔记] 01 工作区和GOPATH

    Go语言3个环境变量: GOROOT:GO语言按照根路径,也就是GO语言的安装路径. GOPATH:若干工作区目录的路径.是我自己定义的工作空间. GOBIN:GO程序生成的可执行文件(executa ...

  9. xml基础学习笔记01

    注意:刚刚看了网上对于XML中的标签,节点和元素?到底应该怎么表述?起初我也有这个疑惑,现在我的想法是:下面出现node的应称作节点,节点对象.element应称作元素,毕竟这更符合英文的本意.至于标 ...

随机推荐

  1. bootstrap-datetimepicker.js学习

    之前项目运用到了这个时间控件,期间bug还是一些.抽个时间,简单地看一下. 先看一下datetimepicker.js的结构 var DateTimePicker = function(element ...

  2. IOS开发初步

    由于工程实践项目的原因,得学习下IOS开发,今天才知道苹果09年才出的开发工具和开发包,也就是说,满打满算,现在顶多有5年IOS开发的工作经验.在我国2010年才火起来,因为那时候国内的iphone4 ...

  3. inuit.css – 基于 Sass 的强大,可扩展的 CSS 框架

    inuit.css 是一个强大的,可扩展的 CSS 框架,另外还是基于 Sass,面向对象的框架.inuit.css 是建立在 BEM 风格的命名约定,非常适合于想要专注于创意而不是代码的设计师以及喜 ...

  4. plsql修改表报错:ORA-25150

    几次通过plsql修改表结构出现这个错误,为人不求甚解真是要不得.我甚至对老大大言不惭的说没有权限,即便是sql语句都不行.结果赤果果地打脸. 最终找到如下原因: 1.操作用户表空间的默认值问题: 这 ...

  5. 200、301、302、304、404等HTTP状态码

    在网站建设的实际应用中,容易出现很多小小的失误,就像mysql当初优化不到位,影响整体网站的浏览效果一样,其实,网站的常规http状态码的表现也是一样,Google无法验证网站几种解决办法,提及到由于 ...

  6. 基于HT的CSG功能构建HTML5的3D书架

    构造实体几何CSG全称Constructive solid geometry,是3D计算机图形学中构建模型的常用技术,可通过合并Union.相减Subtraction和相交Intersction的三种 ...

  7. 用Qt写软件系列五:一个安全防护软件的制作(2)

    引言 在上一篇中讲述了主窗体的创建和设计.主窗体的无边框效果.阴影效果.拖动事件处理.窗体美化等工作在前面的博客中早就涉及,因此上篇博文中并未花费过多笔墨.这一篇继续讲述工具箱(Tool Button ...

  8. MySQL 5.1 参考手册CHM (官方 简体中文版)

    点此下载: MySQL 5.1 参考手册CHM (官方 简体中文版) 在线文档:http://doc.mysql.cn/mysql5/refman-5.1-zh.html-chapter/

  9. MySQL 函数大全

    mysql函数大全 对于针对字符串位置的操作,第一个位置被标记为1. ASCII(str) 返回字符串str的最左面字符的ASCII代码值.如果str是空字符串,返回0.如果str是NULL,返回NU ...

  10. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)

    这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...