Chinaunix首页 | 论坛 | 博客
  • 博客访问: 817607
  • 博文数量: 62
  • 博客积分: 526
  • 博客等级: 二等列兵
  • 技术积分: 2078
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-04 20:41
个人简介

博客迁移至 freefe.cc

文章分类

全部博文(62)

分类: JavaScript

2013-12-02 16:11:18


Jquery 对象


    一般来说,我们都将 Jquery 对象视为一个数组,精确点的说是视为一个类数组对象,可以直接使用 1 2 3 4 5等下标取得所需要的DOM元素或者其他。

    练手自己的函数库的时候,便遇到了一些关于实现上的问题,我有一个 $ 的模块,很简单是返回一个包含查询结果的DOM数组,然后又有了一个关于处理 CSS 的模块,那么如果两个模块不相干 直接可以想这样的使用:

  1. CSS.addClass( $(".classOne"), "classTwo" );

显然也没什么问题,不过就是看上去不那么顺畅,比不上:

  1. $(".classOne").addClass( "classTwo" );

那么的舒服,于是就想整合在一起。

相当于需要将许多是关乎于 DOM 的操作的方法放置到 $ 产生的对象的原型链上,于是问题来了,我的 $ 模块中由于需要判断各种情况 所以基本均是使用 return [] 的方式得到的结果,[] 原型链上只有 Array.prototype 和 Object.prototype 当然不能说在这两个对象上添加 addClass 等方法。

然后就认为,那么不适用 return [] 这种方式,而是得到一个 new 出来的对象,该对象的原型链上添入所需要的方法即可。
可是对于需要对参数做各种判断在实现的函数不使用return实在是不现实。


  1. function $(str,root){
  2.     var elements = [],
  3.     ele_len = 0,
  4.     reg_spl = /\s*,\s*/,
  5.     reg_white = /^\s+|\s+$/,
  6.     dom_obj = {},
  7.     ret = [],
  8.     root = root || d,
  9.     element,i,name;

  10.     if(str.nodeType){ return [str]; }

  11.     if(typeof str !== "string"){ return []; }

  12.     // 单个情况
  13.     if(str.indexOf(",") === -1){
  14.         return getDomObj(str,root);
  15.     }

  16.     elements = str.split(reg_spl);
  17.     ele_len = elements.length;
  18.     for(i = 0; i<ele_len; i++){
  19.         dom_obj = getDomObj(elements[i],root);
  20.         ret = ret.concat(dom_obj);
  21.     }
  22.     return ret;
  23. }


  24. function getDomObj(str, root){
  25.     if(root.querySelectorAll){
  26.         return slice.call(root.querySelectorAll(str));
  27.     }else{
  28.         if(str.indexOf("#")){
  29.             str = str.slice(1);
  30.             return [d.getElementById(str)];
  31.         }else if(str.indexOf(".")){
  32.             str = str.slice(1);
  33.             return getByClass(str,root);
  34.         }else{
  35.             return slice.call(root.getElementsByTagName(str));
  36.         }
  37.     }
  38. }

实在无法改动。

Jquery的实现

    那么Jquery那边是如何实现的,很简答,使用 return 但是是 return this;
    不但可以在各个判断之处及时跳出函数返回结果,也可以方便的控制其原型链。

简单的类Jquery的结构



  1. var jQ = function( selector, context ) {
  2.     return new jQ.fn.init( selector, context );
  3. }
  4. jQ.fn =jQ.prototype = {}
  5. jQ.fn.init = function( selector, context ) {
  6.     this[0] = document.getElementById(selector); // #开头某一个情况
  7.     this.length=1;
  8.     return this;
  9. }
  10. jQ.fn.init.prototype = jQ.fn;
  11. jQ.fn.abc = 1;

那么 所有 jQ 生成的对象可以在内部判断中适当的情况及时 return 出,并且 jQ对象原型链上包含对象 jQ.fn.init.prororype,即 jQ.fn,即 jQ.prototype。所有的 jQ 对象均可以访问 abc 属性。当然,之所以这里这么绕,也和Jquery的自身结构与实现方式有关。

那么:

  1. // 模块中的部分代码结构

  2. // 几个基本选择器方法
  3. function getDomObj(str, root){
  4.     if(root.querySelectorAll){
  5.         return slice.call(root.querySelectorAll(str)); //使用内置方法
  6.     }else{
  7.         if(str.indexOf("#")){
  8.             str = str.slice(1);
  9.             return [d.getElementById(str)];
  10.         }else if(str.indexOf(".")){
  11.             str = str.slice(1);
  12.             return getByClass(str,root);
  13.         }else{
  14.             return slice.call(root.getElementsByTagName(str));
  15.         }
  16.     }
  17. }

  18. function getByClass(classname, root){
  19.     var elements, doms = [], len;
  20.     if(root.getElementsByClassName){
  21.         return slice.call(root.getElementsByClassName(classname))
  22.     }else{
  23.         elements = root.getElementsByTagName("*");
  24.         len = elements.length;

  25.         each(elements, function(ele){
  26.             if((" " + ele.classname + " ").indexof(" "+str+" ") !== -1){
  27.                 doms.push(ele);
  28.             }
  29.         });
  30.         return doms;
  31.     }
  32. }

  33. // 转化类数组形似的 each
  34. function likeArrayEach( nObj, iterator, context){
  35.     var arr = [], i, len = nObj.length;

  36.     for (i=0; i<len; i++) {
  37.         if( nObj[i] ){
  38.             arr[i] = nObj[i];
  39.         }
  40.     };

  41.     each( arr, iterator, context )
  42. }

  43. function dealClass( classStr ){
  44.     var classesName = [],
  45.         classStr = trim( classStr );

  46.     return classStr.split(/\s+/g);
  47. }

  48. //为了可以继承DOM的一般方法,将DOM数组信息放入实例对象中
  49. function markNObject( array, obj ){
  50.     for( var i=0,len=array.length; i<len; i++ ){
  51.         obj[i] = array[i];
  52.     }
  53.     obj.length = len;
  54.     return obj;
  55. }


  56. /** 微型选择器 $
  57. *
  58. * @method $ 目前只支持简单的复合选着 如$("#id, .classname") & $("#id") & $("#id1,#id2")
  59. * 暂不支持层级选着 如 $("#id tag")
  60. * @param {String} str 必选,选择字符串
  61. * @param {Object} obj 可选 选择节点的区域
  62. *
  63. * @return {Array} 返回目标DOM对象数组
  64. *
  65. */
  66. function $(str,root){ // $(".classname") & $("#id") & $("#id1,#id2")
  67.     var elements = [], // 分割后的数组
  68.         ele_len = 0, // 数组长度
  69.         reg_spl = /\s*,\s*/, // 截取
  70.         reg_white = /^\s+|\s+$/,
  71.         dom_obj = {}, // dom 对象
  72.         ret = [], // 返回的dom对象
  73.         root = root || d,
  74.         element,i,name;

  75.     // 参数为DOM对象
  76.     if(str.nodeType){
  77.         this[0] = str;
  78.         this.length = 1;
  79.         return this;
  80.     }

  81.     //不为string返回空数组
  82.     if(typeof str !== "string"){
  83.         this.length=0;
  84.         return this;
  85.     }

  86.     // 单个情况
  87.     if(str.indexOf(",") === -1){
  88.         return markNObject( getDomObj(str,root), this);
  89.     }

  90.     elements = str.split(reg_spl);
  91.     ele_len = elements.length;

  92.     for(i = 0; i<ele_len; i++){
  93.         dom_obj = getDomObj(elements[i],root);
  94.         ret = ret.concat(dom_obj);
  95.     }
  96.     
  97.     return markNObject( ret, this);
  98. }

  99. $.prototype = {
  100.     constructor : $,

  101.     addClass : function( classes ){
  102.         var self = this;
  103.         if( !isArray(classes) ){
  104.             classes = [classes];
  105.         }

  106.         likeArrayEach( self, function( dom ){
  107.             var classStr = dom.className,
  108.                 oldclasses = dealClass( classStr ),
  109.                 newclasses;

  110.                 newclasses = arrayUtil.mergeRepeatArray( classes, oldclasses );

  111.                 dom.className = newclasses.join(" ");
  112.         } );

  113.         return this;
  114.     },
  115.     deleteClass : function( classes ){
  116.         var self = this;
  117.         if( !isArray(classes) ){
  118.             classes = [classes];
  119.         }

  120.         likeArrayEach( self, function( dom ){
  121.             var classStr = dom.className,
  122.                 oldclasses = dealClass( classStr ),
  123.                 newclasses;

  124.                 newclasses = arrayUtil.deleteRepeat( oldclasses, classes );

  125.                 dom.className = newclasses.join(" ");
  126.         } );

  127.         return this;
  128.     },

  129.     hide : function(){
  130.         var self = this;
  131.         markNObject( self, function( dom ){
  132.             dom.style.display = "none";
  133.         } );

  134.         return this;
  135.     },
  136.     show : function(){
  137.         var self = this;
  138.         markNObject( self, function( dom ){
  139.             dom.style.display = "block";
  140.         } );

  141.         return this;
  142.     },

  143.     extend : function( obj ){
  144.         extend( $.prototype, obj );
  145.         return this;
  146.     }
  147. }

上面为选择器模块中的部分代码。











阅读(4113) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~