• 构建一个类jq的函数库


    jqfree core

    var $ = function(selector, context) {  

        return new $.fn.init(selector, context);

    };

    $.fn = $.prototype;

    $.fn.init = function(selector, context) {

        if (selector.nodeType === 1) {

            this[0] = selector;

            this.length = 1;

            return this;

        }

        var parent = context || document;

        var nodeList = parent.querySelectorAll(selector);

        this.length = nodeList.length;

        for (var i=0; i<this.length; i+=1) {

            this[i] = nodeList[i];

        }

        return this;

    };

    $.fn.init.prototype = $.fn;

    我们需要一个包装着DOM Elements的伪数组,此伪数组对象使用原型链去挂载共享的DOM处理方法,原理如下图。

    //选择器

    $('body'); //返回$.fn.init {0: body, length: 1, selector: "body"}

    $('.class');

    $('#id');

    $('#id .class');

    extend

    jqfree中的extend函数参照了prototype.js的实现方式,$.extend和$.fn.extend功能相同,也都是通过浅拷贝的方式,把第二个参数上的对象扩展添加到第二个参数的对象上,如果没有指定第二个参数,则会把第一个参数添加到this上。需要给DOM元素添加方法的话,使用$.fn.extend如$.fn.append,而需要给全局$对象添加扩展的话,使用$.extend,如$.ajax。

    $.extend = $.fn.extend = function (destination, source) {

        //if source is not exist,copy the destination to this。

        if (typeof source === 'undefined') {

            source = destination;

            destination = this;

        }

        for (var property in source) {

            if (source.hasOwnProperty(property)) {

                destination[property] = source[property];

            }

        }

        return destination;

    };

    traverse

    遍历jqfree对象中的DOM Elements。实际上是遍历了$.fn.init {0: body, length: 1, selector: "body"}这样的一个伪数组中的类似数组的那一部分。

    $.fn.extend({

        each: function (func) {

            var i=0,

                length = this.length;

            for (; i<length; i+=1) {

                func.call(this[i], this[i], i);

            }

            return this;

        },

    });

    接受一个回调函数,其第一个参数为dom元素,第二个参数为序号,调用代码如

    $('body').each(function(val, index){

        console.log(val, index)

    });

    DOM processor。

    文档操作。添加了append,prepend,remove,empty的方法,功用同原版jquery。因为生成的$.fn.init是个包含DOM的伪数组,所以操作中就需要遍历这个数组做append操作,目的是为了让选中的所有DOM元素都append一遍。appendChild为DOM level2方法,从IE6开始就支持。

    $.fn.extend({

        append: function (child) {

            if ($.isString(child)) {

                child = $(child)[0];

            }

            this.each(function(v, k) {

                v.appendChild(child);

            });

            child = null;

            return this;

        },

    });

    调用代码如

    var element = document.createElement('div');  

    $('body').append(element);

    css

    添加了css的方法,功用同原版jquery。现将css规则转为驼峰式,然后利用style属性插入,如 padding: 0px; max- 100%; clear: both; min-height: 1em; white-space: pre-wrap; color: rgb(62, 62, 62); font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif; font-size: 16px; line-height: 25.6px; box-sizing: border-box !important; word-wrap: break-word !important;">

    $.fn.extend({

        css: function (cssRules, value) {

            //中划线转为驼峰式

            var transformHump = function (name) {

                return name.replace(/-(w)/g, function(all, letter){

                    return letter.toUpperCase();

                });

            };

            if ($.isString(cssRules)) {

                if ($.isUndefined(value)) {

                    return this[0].style[transformHump(cssRules)];

                } else {

                    this[0].style[transformHump(cssRules)] = value;

                }

            } else {

                for (var i in cssRules) {

                    this[0].style[transformHump(i)] = cssRules[i];

                }

            }

            return this;

        },

    });

    支持两种写法,参数1和参数2可以互为键值对,或者参数1为一个对象,另外这里只第一个dom元素的css规则生效。调用代码如

    //设置第一个body元素的color值

    $('body').css('color', '#FFF');

    $('body').css({

        color: '#FFF',

        background: 'green'

    });

    DOM filter

    添加了dom过滤的几个函数,如children、parent、siblings。返回出去的DOM对象会再次被$.fn.init对象包装。

    $.fn.extend({

        children: function (selector) {

            return $(selector, this[0]);

        }

    });

    只对第一个DOM元素生效,调用代码如下:

    $('body').children('.class'); //获取第一个body元素下的所有class名为'.class'的元素

    attributes

    获取属性,实现了attr,removeAttr,addClass,hasClass,removeClass,data,html这几个api,功能和jq相似。 拿addClass举例来说,classList为H5的API,不支持IE9及以下。所有被匹配的dom元素都会被addClass处理。

    $.fn.extend({

        addClass: function (className) {

            this.each(function(v, k) {

                //please use 'v.className += className' if you need support IE9.

                v.classList.add(className);

            });

            return this;

        },

    });

    调用方式如下:

    $('body').addClass('someClass');

    event

    事件操作。绑定事件使用on,取消绑定事件使用off,触发事件使用trigger。拿on举例,直接使用了addEventListener监听,不支持IE8及以下。需要支持IE8级以下的话,请使用attachEvent兼容。

    $.fn.extend({

        on: function (event, func) {

            this.each(function(v, k) {

                //dom level 2,IE8 not support。

                v.addEventListener(event, func, false);

            });

            return this;

        },

    });

    第一个参数为事件名,第二个参数为回调,调用代码如下:

    $('body').on('click', function(e){

        console.log('click');

    })

    effect

    其他效果,鉴于动画用css3会更直观,所以这里只实现了show和hide两个方法。所有匹配的DOM元素都会被影响,这里只是简单设置了display属性为block或者none,有待改进。

    $.fn.extend({

        show: function() {

            this.each(function() {

               this.style.display = 'block';

            });

            return this;

        },

    });

    调用代码如下:

    $('body').hide();

    ajax

    抽离jsonp,$.jsonp独立于$.ajax,毕竟jsonp的原理和ajax完全没有关系,如果使用$.ajax的话有些误导别人。 $.ajax和$.jsonp方法最后都会返回一个Promise对象,此Promise参照了这里的方案。

    $.ajax只接受一个对象作为参数,并且支持使用promise的写法,调用如下

    $.ajax({

        url: '/test.json'

    })

    .then(function (d) {

        console.log(d);

        return $.ajax({

            url: '/test.json'

        })

    }, function (d) {

        console.log(d);

    })

    .then(function (d) {

        console.log(d);

    }, function (d) {

        console.log(d);

    });

    $.jsonp({

        url: '/test.json',

    })

    .then(function (d) {

        console.log(d);

        return $.jsonp({

            url: '/test.json'

        })

    }, function (d) {

        console.log(d);

    })

    .then(function (d) {

        console.log(d);

    }, function (d) {

        console.log(d);

    });

     

    注意,本地没法测试ajax函数,如果有需要请在此项目目录下运行node server.js,接着去打开test.html文件的关于ajax的注释,再去localhost:3000/test.html就能看到测试ajax的内容。

    cookie

    将增删改查cookie操作都用一个函数搞定

    $.extend({

        cookie: function (cookieName, cookieValue, day) {

            var readCookie = function (name) {

                var arr,

                    reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'),

                    matched = document.cookie.match(reg);

                if(arr = matched) {

                    return unescape(arr[2]);

                } else {

                    return null;

                }

            };

            var setCookie = function (name, value, time) {

                var Days = time || 30;

                var exp = new Date();

                exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);

                document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();

            };

            if (cookieName && cookieValue) {

                //set cookie

                setCookie(cookieName, cookieValue, day);

            } else if (cookieName && $.isNull(cookieValue)) {

                //delete cookie

                setCookie(cookieName, '', -1);

            } else if (cookieName) {

                //read cookie

                return readCookie(cookieName);

            }

        }

    });

    调用代码如下:

    //添加cookie,前两个参数为cookie名和值,必填。第三个参数设置cookie有效时常,单位为天,可选。

    $.cookie('test', 'content');

    //读取cookie,只填第一个参数

    $.cookie('test'); //"content"

    //删除cookie, 第二个参数填null

    $.cookie('test', null);

    utils

    添加了变量类型判断、时间解析函数、url解析函数、浮点数四舍五入小数位和获取随机位数字符串的辅助函数。

    $.extend({

        isUndefined: function(obj) {

            return obj === void 0;

        },

        isNull: function(obj) {

            return obj === null;

        },

        isBoolean: function(obj) {

            return Object.prototype.toString.call(obj) === '[object Boolean]';

        },

        isNumber: function(obj) {

            return Object.prototype.toString.call(obj) === '[object Number]';

        },

        isString: function(obj) {

            return Object.prototype.toString.call(obj) === '[object String]';

        },

        isNaN: function(obj) {

            return obj !== obj;

        },

        isFunction: function(obj) {

            return typeof obj === 'function';

        },

        ......

    });

    $.extend({

        //$.parseTime(new Date().getTime(), 'YYYY-MM-DD hh:mm:ss')

        //result: "2016-08-03 16:14:12"

        parseTime: function (timeStamp, format) {

            var date = new Date(timeStamp);

            var o = {

                'M+' : date.getMonth() + 1, //month

                'D+' : date.getDate(), //day

                'h+' : date.getHours(), //hour

                'm+' : date.getMinutes(), //minute

                's+' : date.getSeconds(), //second

                'S' : date.getMilliseconds() //millisecond

            }

            if(/(Y+)/.test(format)) {

                format = format.replace(RegExp.$1,

                    (date.getFullYear() + '').substr(4 - RegExp.$1.length));

            }

            for(var k in o) {

                if (new RegExp('('+ k +')').test(format)) {

                    format = format.replace(RegExp.$1,

                        RegExp.$1.length == 1 ? o[k] : ('00'+ o[k]).substr((''+ o[k]).length));

                }

            }

            return format;

        },

        //$.parseUrl(location.href)

        //return an object contains the folling info.

        parseUrl: function (url) {

            var a =  document.createElement('a');

            a.href = url;

            return {

                source: url,

                protocol: a.protocol.replace(':',''),

                host: a.hostname,

                port: a.port,

                query: a.search,

                params: (function(){

                    var ret = {},

                        seg = a.search.replace(/^?/,'').split('&'),

                        len = seg.length, i = 0, s;

                    for (;i<len;i++) {

                        if (!seg[i]) { continue; }

                        s = seg[i].split('=');

                        ret[s[0]] = s[1];

                    }

                    return ret;

                })(),

                file: (a.pathname.match(//([^/?#]+)$/i) || [,''])[1],

                hash: a.hash.replace('#',''),

                path: a.pathname.replace(/^([^/])/,'/$1'),

                relative: (a.href.match(/tps?://[^/]+(.+)/) || [,''])[1],

                segments: a.pathname.replace(/^//,'').split('/')

            };

        },

        //$.toFixedFloat(15.658, 2)

        //result: 15.66

        toFixedFloat: function (value, precision) {

            var power = Math.pow(10, precision || 0);

            return String(Math.round(value * power) / power);

        },

        //for generate random string

        //$.generateRandomAlphaNum(5)

        //random result: like "rc3sr".

        generateRandomAlphaNum: function (len) {

            var rdmString = '';

            for (; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));

            return rdmString.substr(0, len);

        }

    });

    调用如下:

    //参数1是时间戳,参数2是格式,年为Y,月为M,日为D,时h,分m,秒s,毫秒S,注意大小写,多余的位数补0

    $.parseTime(new Date().getTime(), 'YYYY-MM-DD hh:mm:ss'); //"2016-08-03 16:14:12"。

    //参数为url链接

    $.parseUrl(location.href); //返回一个带诸多url信息的对象。

    //参数1是目标浮点数,参数2是保留到第几位小数

    $.toFixedFloat(15.658, 2); //四舍五入到两位小数:15.66

    //参数为生成随机的字符串长度

    $.generateRandomAlphaNum(5); //如"rc3sr"

     

  • 相关阅读:
    洛谷 P1494 [国家集训队]小Z的袜子 /【模板】莫队
    洛谷 P2801 教主的魔法
    数据库三范式
    vi和vim三种常见模式
    linux目录结构的具体介绍
    Linux怎么用root用户登录
    虚拟机的网络连接的三种方式
    事务
    数据库存储引擎
    delete和truncate
  • 原文地址:https://www.cnblogs.com/liulinjie/p/5780789.html
Copyright © 2020-2023  润新知