MooTools源码分析

Mootools源码分析二十二

时间:2015-06-28 11:52来源:网络整理 作者:KKWL 点击:
//跟Selector有关的对Document和Element的扩展实现 Native.implement([Document, Element], { //根据查询表达式获取子节点 getElements: function(expression, nocash){ //拆分查询表达式 expression = expression.split(',');

//跟Selector有关的对Document和Element的扩展实现
Native.implement([Document, Element], {
 

 //根据查询表达式获取子节点
 getElements: function(expression, nocash){
  //拆分查询表达式
  expression = expression.split(',');
  var items, local = {};
  for (var i = 0, l = expression.length; i < l; i++){
   //根据查询条件搜索匹配的节点
   var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
   //如果找到节点集合,转为数组类型
   if (i != 0 && elements.item) elements = $A(elements);
   //加到items数组中
   items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
  }
  //返回Elements集合
  return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
 }
 
});

//跟Selector有关的对Element的扩展实现
Element.implement({
 
 //判断当前节点是否匹配指定模式
 match: function(selector){
  if (!selector) return true;
  //根据选择符解释出标签名和id
  var tagid = Selectors.Utils.parseTagAndID(selector);
  var tag = tagid[0], id = tagid[1];
  //当前节点不匹配ID或标签中的任一个都返回false
  if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
  //根据选择符匹配
  var parsed = Selectors.Utils.parseSelector(selector);
  return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
 }
 
});

//声明为简单对象,搭个框架等待后续的填充处理
var Selectors = {Cache: {nth: {}, parsed: {}}};

Selectors.RegExps = {
 //查询表达式中对id的匹配模式
 id: (/#([\w-]+)/),
 //查询表达式中对标签名的匹配模式
 tag: (/^(\w+|\*)/),
 //查询表达式中对快速模式的匹配模式
 quick: (/^(\w+|\*)$/),
 //查询表达式中对分隔符的匹配模式
 splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
 //组合模式 
 combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
};

//一些辅助的工具方法
Selectors.Utils = {

 //检查item是否重复
 chk: function(item, uniques){
  if (!uniques) return true;
  //总是返回当前元素的唯一id
  var uid = $uid(item);
  //如果不存在,说明集合中还没有此项,置为true返回
  if (!uniques[uid]) return uniques[uid] = true;
  return false;
 },
 
 /*
 解释nth查询时的参数
 nth表示对第n个的查询,见
 */
 parseNthArgument: function(argument){
  //如果曾经按相同参数查询过,返回缓存的结果,不错的策略,避免每次重新计算
  if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
  //解释nth查询的参数
  var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
  if (!parsed) return false;
  //第一个数值
  var inta = parseInt(parsed[1]);
  //inta没值时a默认为1
  var a = (inta || inta === 0) ? inta : 1;
  //命名部分
  var special = parsed[2] || false;
  //第二个数值
  var b = parseInt(parsed[3]) || 0;
  if (a != 0){
   b--;
   while (b < 1) b += a;
   while (b >= a) b -= a;
  } else {
   a = b;
   special = 'index';
  }
  switch (special){
   case 'n': parsed = {a: a, b: b, special: 'n'}; break;
   case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
   case 'even': parsed =  {a: 2, b: 1, special: 'n'}; break;
   case 'first': parsed = {a: 0, special: 'index'}; break;
   case 'last': parsed = {special: 'last-child'}; break;
   case 'only': parsed = {special: 'only-child'}; break;
   default: parsed = {a: (a - 1), special: 'index'};
  }
  
  return Selectors.Cache.nth[argument] = parsed;
 },
 
 //解释选择符
 parseSelector: function(selector){
  //同样的缓存策略
  if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
  var m, parsed = {classes: [], pseudos: [], attributes: []};
  //注意正则的exec和match的区别
  while ((m = Selectors.RegExps.combined.exec(selector))){
   //匹配结果依次为:CSS类名,属性名,属性操作符,属性值,伪类名,伪类属性
   var cn = m[1], an = m[2], ao = m[3], av = m[4], pn = m[5], pa = m[6];
   if (cn){
    //加到CSS类名集合
    parsed.classes.push(cn);
   } else if (pn){
    var parser = Selectors.Pseudo.get(pn);
    //如果存在伪类名,pa作为伪类参数
    if (parser) parsed.pseudos.push({parser: parser, argument: pa});
    //否则作为属性比较的右值
    else parsed.attributes.push({name: pn, operator: '=', value: pa});
   } else if (an){
    //属性比较
    parsed.attributes.push({name: an, operator: ao, value: av});
   }
  }
  //如果选择符中不存在CSS类名的查询,删除classes属性
  if (!parsed.classes.length) delete parsed.classes;
  //如果选择符中不存在Element属性的查询,删除attributes属性
  if (!parsed.attributes.length) delete parsed.attributes;
  //如果选择符中不存在伪类的查询,删除pseudos属性
  if (!parsed.pseudos.length) delete parsed.pseudos;
  //如果三者都不存在,置null
  if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
  //缓存结果并返回
  return Selectors.Cache.parsed[selector] = parsed;
 },
 
 //解释查询表达式中的标签名和id
 parseTagAndID: function(selector){
  //匹配标签名
  var tag = selector.match(Selectors.RegExps.tag);
  //匹配id
  var id = selector.match(Selectors.RegExps.id);
  //没有匹配标签时用星号'*'代替,没有匹配id时返回false
  return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
 },
 
 filter: function(item, parsed, local){
  var i;
  //根据CSS类名匹配
  if (parsed.classes){
   for (i = parsed.classes.length; i--; i){
    var cn = parsed.classes[i];
    if (!Selectors.Filters.byClass(item, cn)) return false;
   }
  }
  //根据属性匹配
  if (parsed.attributes){
   for (i = parsed.attributes.length; i--; i){
    var att = parsed.attributes[i];
    if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
   }
  }
  //根据伪类匹配
  if (parsed.pseudos){
   for (i = parsed.pseudos.length; i--; i){
    var psd = parsed.pseudos[i];
    if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
   }
  }
  return true;
 },
 
 //根据标签名和ID查找Element
 getByTagAndID: function(ctx, tag, id){
  //如果提供id
  if (id){
   //先根据id查找到Element
   var item = ctx.getElementById(id, true);
   //再根据标签名过滤
   return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
  } else {
   //不提供id时直接查找满足标签名的Element
   return ctx.getElementsByTagName(tag);
  }
 },
 
 //查找
 search: function(self, expression, local){
  //查询表达式的按分隔符分割出来的操作符
  var splitters = [];
  /*
  根据分隔符切割查询表达式,看来expression中不能包含':)'
  替换函数中m0是整个匹配的字符串,m1为+>~和空白之类的字符,m2为子表达式内容
  */
  var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
   splitters.push(m1);
   return ':)' + m2;
  }).split(':)');
  
  var items, match, filtered, item;
  
  for (var i = 0, l = selectors.length; i < l; i++){
   
   var selector = selectors[i];
   
   //匹配quick模式意味着可以使用标签名匹配查找
   if (i == 0 && Selectors.RegExps.quick.test(selector)){
    items = self.getElementsByTagName(selector);
    continue;
   }
   
   var splitter = splitters[i - 1];
   
   //解释出标签名和id
   var tagid = Selectors.Utils.parseTagAndID(selector);
   var tag = tagid[0], id = tagid[1];

   if (i == 0){
    //在首位时的处理
    items = Selectors.Utils.getByTagAndID(self, tag, id);
   } else {
    //先按标签名,id和操作符查找所有匹配项
    var uniques = {}, found = [];
    for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
    items = found;
   }
   
   //根据其它选择符过滤
   var parsed = Selectors.Utils.parseSelector(selector);
   
   if (parsed){
    filtered = [];
    for (var m = 0, n = items.length; m < n; m++){
     item = items[m];
     //过滤匹配
     if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
    }
    items = filtered;
   }
   
  }
  
  return items;
  
 }
 
};


------分隔线----------------------------