博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
zepto源码研究 - zepto.js - 1
阅读量:4958 次
发布时间:2019-06-12

本文共 6869 字,大约阅读时间需要 22 分钟。

简要:网上已经有很多人已经将zepto的源码研究得很细致了,但我还是想写下zepto源码系列,将别人的东西和自己的想法写下来以加深印象也是自娱自乐,文章中可能有许多错误,望有人不吝指出,烦请赐教。

首先是整个大致流程:

Zepto  的整体结构 var Zepto = (function() {  //实际构造函数` function Z(dom, selector) { var i, len = dom ? dom.length : 0 for (i = 0; i < len; i++) this[i] = dom[i] this.length = len this.selector = selector || '' } zepto.Z = function(dom, selector) { return new Z(dom, selector) } //是否Zepto对象    instanceof 会循环查找左边的_prop_和右边的原型链中的原型是否匹配 zepto.isZ = function(object) { return object instanceof zepto.Z } // 初始化参数、DOM zepto.init = function(selector, context) { ... return zepto.Z(dom, selector) } //构造函数 $ = function(selector, context){ return zepto.init(selector, context) } //原型设置 $.fn = { ... } zepto.Z.prototype = Z.prototype = $.fn $.zepto = zepto return $ })() // If `$` is not yet defined, point it to `Zepto` window.Zepto = Zepto window.$ === undefined && (window.$ = Zepto)

zepto开头就是变量的初始化: concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice,由于这些变量会经常用到,因此在这里缩短作用域链是优化的一种方法。

接下来是正则表达式:

//匹配HTML代码      fragmentRE = /^\s*<(\w+|!)[^>]*>/,  //TODO 匹配单个HTML标签      singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,  //TODO 匹配自闭合标签      tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,  //匹配根节点      rootNodeRE = /^(?:body|html)$/i,  //匹配A-Z      capitalRE = /([A-Z])/g,

zepto.matches :

/**   * 元素是否匹配选择器   * @param element   * @param selector   * @returns {*}   */  zepto.matches = function(element, selector) {    //没参数,非元素,直接返回    if (!selector || !element || element.nodeType !== 1) return false    //如果浏览器支持MatchesSelector  直接调用    var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||        element.oMatchesSelector || element.matchesSelector    if (matchesSelector) return matchesSelector.call(element, selector)    //浏览器不支持MatchesSelector    var match, parent = element.parentNode, temp = !parent    //元素没有父元素,存入到临时的div tempParent    if (temp) (parent = tempParent).appendChild(element)    //再通过父元素来搜索此表达式。  找不到-1  找到有索引从0开始    //注意 ~取反位运算符  作用是将值取负数再减1   如-1变成0  0变成-1    match = ~zepto.qsa(parent, selector).indexOf(element)    //清理临时父节点    temp && tempParent.removeChild(element)    //返回匹配    return match  }
elem.matchesSelector(selector)  判断元素elem 是否匹配 selector, 例如:
$("#id").click(function (e) {            if(e.target.matches('a.btn')) {                e.preventDefault();                //TODO something            }        });

如果matchesSelector不支持,则找出elem的父元素(若没有则创造一个)利用zepto.qsa(parent, selector)来找出满足条件的元素

zepto.qsa(parent, selector):

 

/**   *  通过选择器表达式查找DOM   *  原理  判断下选择器的类型(id/class/标签/表达式)   *  使用对应方法getElementById getElementsByClassName getElementsByTagName querySelectorAll 查找   * @param element   * @param selector   * @returns {Array}   */  zepto.qsa = function(element, selector){    var found,        maybeID = selector[0] == '#',//ID标识        maybeClass = !maybeID && selector[0] == '.',//class 标识    //是id/class,就取'#/.'后的字符串,如‘#test’取‘test'        nameOnly = maybeID || maybeClass ? selector.slice(1) : selector,        isSimple = simpleSelectorRE.test(nameOnly)  //TODO:是否为单个选择器  没有空格    return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById        //通过getElementById查找DOM,找到返回[dom],找不到返回[]        ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :        //当element不为元素节点或document fragment时,返回空        //元素element   1   属性attr   2   文本text   3   注释comments   8   文档document   9   片段 fragment 11        (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :            slice.call(                //如果是class,通过getElementsByClassName查找DOM,                isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName                    maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class                        element.getElementsByTagName(selector) : // Or a tag //如果是标签名,调用getElementsByTagName                    //最后调用querySelectorAll                       // Or it's not simple, and we need to query all            )  }

 

 

1:首先判断selector是ID类型还是class类型,将标识先赋值准备好      if(maybeID){
     //如果是Id,则取Id  return found = element.getElementById(nameOnly)?[found]:[] }       if(element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11){       //如果不是正常的节点,则返回空       return []; }else{ if(isSimple&&element.getElementsByClassName){ if(maybeClass){ return element.getElementsByClassName(nameOnly); }else{ return element.getElementsByTagName(selector); } }else{ element.querySelectorAll(selector) } }

 

这里的nodeType 判断 1:是否为element元素,9:是否为document,11:是否为DocumentFragment

引用http://www.cnblogs.com/blueSkys/p/3685740.html中的一句话对DocumentFragment进行解释

DocumentFragment 节点不属于文档树,继承的 parentNode 属性总是 null。

不过它有一种特殊的行为,该行为使得它非常有用,即当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作

element.querySelectorAll(selector)意思是 查找element的子元素并且document内css选择器符合selector的元素(这里并不像jquery.find一样查找 element的符合selector的子元素)
引用http://www.zhangxinxu.com/wordpress/2015/11/know-dom-queryselectorall/里面的内容:
 
document.querySelectorAll("#my-id div div").length === 1;  ---->   
document.querySelector("#my-id").querySelectorAll("div div").length === 3;  ---->  
find:$(element).find(args); $(element)和args都可以是数组,这里主要介绍一下Array.filter和emptyArray.some,
  /*     在当前集合中查找selector,selector可以是集合,选择器,以及节点     */    find: function(selector){      var result, $this = this      //如果selector为node或者zepto集合时      if (!selector) result = $()      //遍历selector,筛选出父级为集合中记录的selector      else if (typeof selector == 'object')        result = $(selector).filter(function(){          var node = this          //如果$.contains(parent, node)返回true,则emptyArray.some也会返回true,外层的filter则会收录该条记录          //Array.some 如果有一个为true,则整体返回为true          return emptyArray.some.call($this, function(parent){            return $.contains(parent, node)          })        });      //如果selector是css选择器      //如果当前集合长度为1时,调用zepto.qsa,将结果转成zepto对象      else if (this.length == 1) result = $(zepto.qsa(this[0], selector))      //如果长度大于1,则调用map遍历      else result = this.map(function(){ return zepto.qsa(this, selector) })      return result    },
Array.filter(function(value){return true}) 将不符合条件的数组元素过滤掉,Array.some(function(){return true}) ,用来检查数组中是否 有满足条件的元素,如果有则返回true,find函数会先处理selector为对象和数组的情况,然后在处理为css选择器的情况。 本文主要介绍zepto的整体流程和初始化操作以及查询选择DOM的具体过程,下一篇具体介绍$()通过zepto.init使如何运作的

转载于:https://www.cnblogs.com/zhutao/p/5642367.html

你可能感兴趣的文章
第四季苹果超越三星成全球最大智能手机厂商
查看>>
使用httpclient 调用selenium webdriver
查看>>
PowerShell应用之-批量还原数据库(支持完整,差异,事务日志)
查看>>
RNA-Seq分析|RPKM, FPKM, TPM, 计算对比
查看>>
MyEclipse获取注册码
查看>>
模块:(日期选择)jquery、bootstrap实现日期下拉选择+bootstrap jquery UI自带动画的日期选择器...
查看>>
函数和对象
查看>>
DOM 解析操作知识
查看>>
动态规划
查看>>
逆序创建单链表
查看>>
LeetCode 521. Longest Uncommon Subsequence I
查看>>
docker方式mysql设置字符集
查看>>
标准输入到绘图过滤器(plotfilter.py)
查看>>
unity TileMap 简述
查看>>
[转]对于孩子:旅行的意义何在?
查看>>
App开发流程之iOS开发证书拾遗
查看>>
gitlab中的几个常用界面(runner管理、gitlab-ci.yml管理、runner token管理、新建用户、拉用户入工程、拉用户入组、复制工程导入组)...
查看>>
js设置输入框失去光标与光标选中时样式
查看>>
时间工具转换工具类
查看>>
利用Python进行数据分析(10) pandas基础: 处理缺失数据
查看>>