zoukankan      html  css  js  c++  java
  • 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{
                 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 result;
    }
    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);
    })
    

    再次体现了封装的意义.

    下面JavaScript高级框架设计(二) 将会开始介绍基本选择器的实现

  • 相关阅读:
    网站安全策略
    防止表单重复提交的几种策略
    Laravel5中防止XSS跨站攻击的方法
    PHP + ORACLE 远程连接数据库环境配置
    iview table表格内容为数组或者对象的子元素时问题讨论
    jquery中 $(xxx).each() 和 $.each()的区别,以及enter键一键登录
    vue.js 强行赋值、刷新数组或者对象 方法之 $.set()
    vue 组件,以及组件的复用
    vue 和 jquery混合使用
    JS清除空格之trim()方法
  • 原文地址:https://www.cnblogs.com/likeFlyingFish/p/5693588.html
Copyright © 2011-2022 走看看