JavaScript 高级框架设计

JavaScript 高级框架设计

在现在,jQuery等框架已经非常完美,以致于常常忽略了JavaScript原生开发,但是这是非常重要的.

所以,我打算写一个简单的框架,两个目的

  • 熟练框架的思想

  • 熟练DOM操作.

所以我打算,模仿jQuery,实现一个简单的类似jQuery的库 Hpawn.

关于JavaScript面向对象高级,会在以后介绍.

关于我所有的代码,都会托管到 github上,https://github.com/apawn

我的开发环境是VSCode.


在Hpawn中,我会分为六个模块.

  • 选择器模块
  • dom操作模块
  • 事件模块(click,on) 比较简单
  • 属性模块
  • 样式模块
  • 动画模块,使用缓动函数而不是css3.
  • 面向对象封装

选择器模块

在这里,我们要实现一个类似于jQuery选择器的东西,但是要简单很多.

代码 01.html

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        div{
            width: 300px;
            height: 100px;
            border: 1px red solid;
        }
    </style>
</head>
<body>
    <div></div>
    <div></div>
 </body>

现在我们要给上面的div添加绿色背景,按照传统的办法,可能会这么写

01.js

   onload = function(){
        var divs = document.getElementsByTagName("div");
        for(var i = 0,length = divs.length;i<length;i++){
                divs[i].style.backgroundColor="green";
        }
    }

但是,这样的DOM操作真的很麻烦.

代码冗余.丑,易错, 还会影响性能,为什么?

因为代码要压缩,因为document.getElementsByTagName()不会改变,但是如果改为get方法,只会存在一个g.

现在开始解决,首先解决代码冗余

02.js

先封装一个get方法

var get = function (tag) {
    return document.getElementsByTagName(tag);
}

代码可能会变成现在这样,

var divs = get("div");
for(var i = 0,length = divs.length;i<length; i++){
        divs[i].style.background = "green"; 
}

但是,似乎还是很冗余,继续封装.

03.js

var get = function (tag) {
    return document.getElementsByTagName(tag);
}
var each = function (arr,style,value) {
    for(var i = 0,length = arr.length;i<length; i++){
        arr[i].style[style] = value;
    }
}


var divs = get("div");
each(divs,"backgroundColor","green") ;

代码变成了上面那样,有木有觉得好了很多呢.

可能并不觉得会简单,那是因为我只包含了两个元素.

但是,上面的代码只能做一件事情,就是设置样式,可是我还设置动作,设置属性.

好了,第一步优化完成,下面开始第二部.

04.js

var get = function (tag) {
    return document.getElementsByTagName(tag);
}
var each = function (arr,func) {
    for(var i = 0,length = arr.length;i<length; i++){
        func(arr[i],i);
    }
}


var divs = get("div");
each(divs,function (item,index) {
   item.style.background = "red"; 
});

我传递了一个函数进去,我将arr[i] 和i 传给函数,这是最关键的一步.

但是,一个问题出现了.

比如,我先查找数组 arr =[1,2,3,4] 中元素为3的索引,上面的代码可以吗?

我找到了,怎么跳出呢?

也许想到这样的代码

each(arr,function(v,i){
  if(v===5){
    breadk;
  }
})

但是,break 可以写在函数中吗??

// 为了查看单独的js代码,我使用了node作为运行环境,所以代码库里有一些并没有对应的html文件.

还是需要再修改each 函数

05.js

 var each = function (arr, func) {
    for (var i = 0, length = arr.length; i < length; i++) {
        if (func(arr[i], i) === false) {
            break;
        }
    }
};

var a = [1, 2, 3, 4];
var index = -1;
each(a, function (v, i) {
    if (v === 3) {
        index = i;
        return false;
    }
});
console.log(index);  // 输出2

这里写图片描述

大功告成!

但是,我们每次调用函数的时候都要传一个v和i 才能使用,如果不小心忘了呢?

似乎有更好的办法

07.js,继续回到第一个例子

var get = function (tag) {
    return document.getElementsByTagName(tag);
}
var each = function (arr, func) {
    for (var i = 0, length = arr.length; i < length; i++) {
        if (func.call(arr[i],arr[i], i) === false) {
            break;
        }
    }
};
var divs = get("div");
each(divs,function (item,index) {
   this.style.background = "red"; 
});

现在,我们看看jQuery的each是怎么实现的.

each: function( obj, callback, args ) {
        var value,
            i = 0,
            length = obj.length,
            isArray = isArraylike( obj );

         else 
            if ( isArray ) {
                for ( ; i < length; i++ ) {
                    value = callback.call( obj[ i ], i, obj[ i ] );

                    if ( value === false ) {
                        break;
                    }
                }
            } else {
                for ( i in obj ) {
                    value = callback.call( obj[ i ], i, obj[ i ] );
                    if ( value === false ) {
                        break;
                    }
                }
        }

        return obj;
    },

是不是差不多呢….

现在,继续优化get方法.

如果用get方法获得多个元素,就会获得多个数组,为了简化开发,可以考虑合并到一个数组中,调用多次get方法.

给get添加一个result参数

var get = function (tag, result) {
    result = result || [];
    result.push.apply(result, document.getElementsByTagName(tag));
    return document.getElementsByTagName(tag);
}
var each = function (arr, func) {
    for (var i = 0, length = arr.length; i < length; i++) {
        if (func.call(arr[i], arr[i], i) === false) {
            break;
        }
    }
};
var divs = get("div");
each(divs, function (item, index) {
    this.style.background = "red";
});

但是,这里为什么要用apply呢?

因为document.getElementsByTagName() 返回一个伪数组,但是push方法只能接受真数组,在这里调用apply,因为apply接受的其他参数必须是一个数组,这里把document.getElementsByTagName() 的返回结果进行展开,然后一个一个push进去.

当然也可以这么写,但是性能肯定不及原生方法性能高.

each( document.getElementsByTagName(tag),function(){
        result.push(this);
})

再次体现了封装的意义.

下面将会开始进入get选择器.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值