【JavaScript框架封装】使用原生js封装的类似于JQuery的框架及核心源码分享(多文件版本)

本文分享了一款使用原生JavaScript封装的类似JQuery框架——Xframe,该框架将各个功能模块化,包括basisModule, stringModule, arrModule等。代码已上传至GitHub,提供主入口文件main.js和功能测试文件index.html,便于读者下载学习和功能验证。" 132349952,19673928,R语言中实现散点图数据点的抖动效果,"['R语言', '信息可视化', '开发语言']
摘要由CSDN通过智能技术生成

这个版本的JQuery是对上一个版本的JQuery,使用了require.js进行了二次封装,基本上把前面的每一个框架封装成为一个单独的模块,最终的目录结构如下:

由于代码量和目录比较多,这个封装好的代码和目录已经全部上传到GitHub上面,需要的同学可以前往下载哈。

https://github.com/xiugangzhang/JavaScript-Xframe

【main.js】这个是模块文件的主入口函数

/**
 * @Desc : 主要的功能模块展示
 * @Author : xiugang
 * @Time : 20180722
 */
//配置项,在主入口js文件配置即可,其他模块都可调用paths模块
require.config({
    //所有的require依赖根路径都是baseUrl
    baseUrl: './js',
    //路径可以是数组,如果第一个加载成功则结束,否则加载后面的文件
    paths:{
        'xframe' : 'xframe',                // 主框架模块
        'basis': 'basisModule',             // 基础模块
        'string': 'stringModule',           // 字符串方法扩展模块
        'array' : 'arrModule',              // 数组方法扩展模块
        'func' : 'funcModule',              // AOP模块
        'domReady' : 'domReadyModule',      // 异步加载模块
        'dom' : 'domModule',                // DOM元素操作模块
        'css' : 'cssModule',                // CSS样式模块
        'attr' : 'attrModule',              // 属性模块
        'content' : 'contentModule',        // 内容模块
        'event' : 'eventModule',            // 事件模块
        'select' : 'selectModule',          // 选择模块
        'animate' : 'animateModule',        // 动画模块
        'cache' : 'cacheModule'             // 缓存模块
    }
});

【index.html】这个是自己封装完毕之后对每一个框架进行的功能测试文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #map{
            width: 250px;
            height: 250px;
            background: #0da357;
            position: absolute;
        }

        #game{
            position: absolute;
            width: 350px;
            height: 350px;
            top: 280px;
            background: blue;
        }
    </style>
</head>
<body>
<div id="map">123456789</div>
<div id="game">789456123</div>
<script data-main="main" src="require.min.js"></script>
<script>
    /**
     * 在这里导入需要使用的模块,以供下面调用的时候来使用
     */
    require([
        'js/domReadyModule',
        'js/xframe',
        'js/stringModule',
        'js/arrModule',
        'js/funcModule',
        'js/basisModule',
        'js/eventModule',
        'js/cssModule',
        'js/selectModule',
        'js/attrModule',
        'js/contentModule',
        'js/domModule',
        'js/animateModule',
        'js/cacheModule'
    ], function (domReadyModule,
                 xframe,
                 stringModule,
                 arrModule,
                 funcModule,
                 basisModule,
                 eventModule,
                 cssModule,
                 selectModule,
                 attrModule,
                 contentModule,
                 domModule,
                 animateModule,
                 cacheModule
    ) {
        console.log(xframe);
        console.log('1234560@{name}'.formateString({name: 'xiuxiu'}), 'redcolor'.camelCase());
        var arr = new Array(1, 2, 5);
        console.log(arr.random(3));
        console.log(funcModule);
        console.log($.isArray(new Array()));
        console.log(domReadyModule);
        // 直接获取一个类似于JQuery的对象
        console.log($('#map'));
        $('#map').on('click', function () {
            this.style.background = 'red';
            console.log($.getEvent());
        });
        //console.log($('#map').getEvent());
        domReadyModule.onReady(function (mes) {
            console.log('load ok', mes);  // ok
        });

        console.log(eventModule);
        console.log(cssModule);
        $(function (mes) {
            console.log(mes); //ok
        })


        // 事件框架测试
        var fun = function () {
            console.log('DOM load 完毕!');
        }
        $(fun);

        console.log(selectModule);

        // 选择框架测试
        var res = $.$id('map');
        console.log(res);

        // CSS样式框架测试
        console.log($('#map').css('width'));
        console.log($('#map').css('background', 'pink'));

        // 属性框架测试[20180721测试-----------------------------]
        console.log(attrModule);
        res = $('#map');


        console.log($('#map').addClass('name'));
        $('#map').addClass('age');
        $('#map').attr('name', 18);

        // 内容框架测试
        console.log($('#map').html('<a href="main.js">7892121212</a>>'));
        console.log(contentModule);


        // DOM框架测试
        console.log(domModule);
        var dom = $.create('div', {name: "xiuxiu"}, '<a>456789</a>');
        dom.appendTo(('#map'));
        console.log(dom);
        var dom1 = $.create('span', {age: "22"}, '<a href="require.min.js">456789</a>');
        dom.append(dom1);

        // 动画框架测试
        console.log(animateModule.Animate);
        $('#map').on('click', function () {
            // $$.animate('#sun', {left: width}, 7000);
            $.animate('#map', {left: 550, top: 550}, 7000)
        });

        //$('#game').css('left', '800px');
        document.getElementById('game').style.left = '800px';


        // backgroundColor
        console.log('background-color'.camelize());

        // 缓存框架的测试
        // 本地临时存储的实现测试
        // set
        // 使用方式,需要先指定需要使用的功能模块名称,然后再指定相应的函数功能
        // 1. 添加数据
        cacheModule.cache.add('name', '52tech');
        // 2.获取数据
        var res = cacheModule.cache.get('name');
        // 3. 修改数据
        res = cacheModule.cache.update('name', 'xiuxiu');
        res = cacheModule.cache.get('name');
        // 3. 删除数据
        res = cacheModule.cache.delete('name');
        // 4.  判断本地是否存在某一个数据
        res = cacheModule.cache.isExist('name');






        // cookie框架测试
        // 1. 添加Cookie信息 name, value, days, path
        // 主要问题: 如果直接添加内容的话,出现的问题是,存储的是这个内容,但是存储进cookie本地存储的就不是了
        // 注意当前的这种方式是不支持在字符串中有分号的情形
        cacheModule.cookie.setCookie('script5', '<script>alert(2)<\/script>', 10, '/');
        // 2. 获取本地存储的cookie信息
        res = cacheModule.cookie.getCookie('script3');
        document.body.innerHTML = '<script>alert("ok")<\/script>';
        // 3. 修改本地的Cookie信息
        res = cacheModule.cookie.deleteCookie('script5', '/');


        // 清空所有的COOkie信息
        // "name&amp=xiuxiu&amp; name=xiuxiu; script=<script>alert(2); script2=<script>alert(2); script3=<script>alert(2); script3&amp=&ltscript&gtalert(2); script4&amp=&ltscript&gtalert(2); a&amp=&lta&gtalert(2)&lt/a&gt&amp"
        cacheModule.cookie.clearAllCookies();

        // 设置Cookie信息
        cacheModule.cookie.setCookie('json', '<a href="www.52tech.tech" onclick="javascript:void 0"></a>>', 10, '/');
        res = cacheModule.cookie.getCookie('json');
        console.log(res);


        // localstorage本地存储功能的测试
        // 1. 设置storage信息
        $.storage.set('name', 'xiuxiu');
        // 2. 获取信息
        res = $.storage.get('name');
        // 3. 修改信息
        $.storage.remove('name');
        // 4. 清空所有的本地存储信息
        $.storage.clear();
    });
</script>
</body>
</html>

【JS文件夹】:这个文件夹就是自己抽象出来的一些功能模块,这也是第一次进行的模块封装,封装的也比较粗糙,但是基本的功能还是实现了,大家可以一起交流哈。

下面的这个就是主框架Xframe模块:

/**
 * 自定义一个基本的模块:类似于JQuery的基础模块,主要用于实现一个链式访问的功能
 */
define(function () {
    // 返回的必须是一个对象
    // 主框架: 只做一件事,就是用于获取所有的元素集合

    // 定义一个Xframe对象,后面就是他的构造函数
    var xframe = function (selector, context) {
        // 为了使得后面的函数this始终指向的是xframe框架,这里需要修改函数内部this的指向
        return this.init.apply(this, [selector, context]);
    };

    // 定义一个初始化函数,用于初始化获取所有的元素集合
    // 只要用户使用了类似于JQuery中的选择元素的方法,就开始选择一个元素集合
    // 这里的核心功能:实际上是为了使用一个伪数组实现一个类似于JQuery中的链式访问的功能
    xframe.prototype.init = function (selector, context) {
        // 开始构建一个伪数组:{1 : list[0], 2 : list[1], , , , length : list.length}
        this.length = 0;

        // 针对没有参数的处理方式
        if (typeof selector === 'undefined') {
            return this;
        }

        if (typeof  selector === 'string') {
            var nodeList = (context || document).querySelectorAll(selector);
            this.length = nodeList.length;
            for (var i = 0, len = this.length; i < len; i++) {
                this[i] = nodeList[i];
            }
        } else if (selector.nodeType) {
            // 如果获取的是一个元素节点,文本节点,或者属性节点的话
            this[0] = selector;
            this.length++;
        }

        // 为了可以支持链式访问必须把这个this对象返回出去
        return this;
    };


    // 使用双对象法则继续暴露出去一个对象,进行对象的二次封装
    // 【双对象法则的使用】
    var $$ = function (selector, context) {
        var self = this;
        // 这里使用一个简单的异步加载机制,等待所有的DOM元素执行完毕之后再开始继续向下执行
        if (typeof selector === 'function') {
            // selector就是DOM元素加载完毕之后的继续向下执行的回调函数
            //w.onload = selector;

            // 使用自己定义的函数来实现一个domReady(ele, fn)的功能, 默认就是整个document加载完毕之后才会继续向下执行
            // 使用call的时候第一个参数不能少哈, 否则传过去的参数就是空的
            //$$.onDOMReady.call(this, selector);

            // 使用apply传参的时候必须传递的是一个数组类型
            //$$.onDOMReady.apply(this, [selector]);

            // 如果使用bind的话(只是会修改调用函数内部的指向, 但是不会调用)
            // bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。【只是会返回一个函数, 但还是不会立即调用】
            require(['js/domReadyModule'], function (domReadyModule) {
                var func = domReadyModule.onReady.bind(self, selector);
                // 调用使用bind()方法返回的函数
                func();
            });
        } else {
            // 如果不是一个函数的话
            return new xframe(selector, context);
        }
    }

    // 添加一个extend方法, 用于扩充一个对象的方法, 扩展向一个类中拷贝方法
    $$.extend = function () {
        // 这里需要分为两种情况:
        // 1. 如果传过来的是一个参数的话,就相当于是给xframe对象添加方法
        // 2. 如果是两个参数的话,就相当于是给一个类扩充方法(把一个函数的方法拷贝到另一个类中去)
        var len = arguments.length,
            target = null,              // target 用来存储需要把方法拷贝进去的目标函数
            i = 1,                      // 初始化变量i, 表示需要开始遍历的起始位置标记
            key;                        // 为了防止定义太多的局部变量,可以把后面需要用到的所有局部变量事先在前面定义好
        if (len === 0) {
            return;
        } else if (len === 1) {
            // 给xrame对象添加方法
            target = xframe.prototype;
            i--;
        } else {
            // 两个参数的话,那么第一个参数就是我需要拷贝新的方法进去的目标对象
            // 如果是两个参数的话:就不需要修改变量i的值了, 直接从第一个位置开始,拿到第一个参数后, 把第二个参数的方法全部拷贝给第一个对象
            // 注意: 这里有可能也是三个参数或者是多个参数, 因此也可以吧后面的好几个对象的属性或者方法添加给第一个对象
            target = arguments[0];
        }


        // 确定好了target 这个目标对象以后,开始遍历原始对象那个source,把source里面的方法全部都拷贝到这个target对象里面
        for (; i < len; i++) {
            // 这里实际上在遍历一个json对象,json对象的每一项实际上就是一个属性或者方法
            // 遍历每一个arguments, 获取每一个参数的属性, 然后把这个属性拷贝到原始的对象
            for (key in arguments[i]) {
                target[key] = arguments[i][key];
            }
        }
        return target;
    }


    var w = window;
    // 为了把主框架里面的局部变量暴露出去供其他模块使用
    w.xframe = w.$ = $$;


    // 把当前的这个对象返回出去即可
    return $$;
});

basisModule.js

/**
 * @Desc : 主要的功能模块展示
 * @Author : xiugang
 * @Time : 20180722
 */
/**
 * 定义一个基础框架,这里的模块名字必须和文件的名字一样
 */
define(['js/xframe'], function (xframe) {
        // 数据类型检验模块
    var api = {};
    // 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。
    // 只关注对象的行为,不关注对象本身面向接口编型 ,而不是面向实现编程,是设计模式中最重要的思想。
    // 【理解】:一个对象有效的语义,不是由集成自特定的类或实现特定的接口, 而是由当前方法和属性的集合决定的!!!
    api.isNeedChainedAccess = function(){

    }
    api.isNotNeedChainedAccess = function(){
        /*数据类型检验*/
        xframe.extend(xframe, {
            // 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。
            // 只关注对象的行为,不关注对象本身面向接口编型 ,而不是面向实现编程,是设计模式中最重要的思想。
            // 【理解】:一个对象有效的语义,不是由集成自特定的类或实现特定的接口, 而是由当前方法和属性的集合决定的!!!
            isNumber: function (val) {
                // 如果这个数字是有限的话, 而且是数字类型
                return (typeof val === 'number' && isFinite(val)) && (Object.prototype.toString.call(val) === '[object Number]');
            },
            /***
             * 判断一个变量是不是Boolean类型
             * @param val
             * @returns {boolean}
             */
            isBoolean: function (val) {
                return (typeof val === 'boolean') && (Object.prototype.toString.call(val) === '[object Boolean]');
            },
            /**
             * 判断一个变量是不是字符串类型
             * @param val
             * @returns {boolean}
             */
            isString: function (val) {
                return (typeof val === 'string') && (Object.prototype.toString.call(val) === '[object String]');
            },
            /**
             * 判断一个变量是不是undefined
             * @param val
             * @returns {boolean}
             */
            isUndefined: function (val) {
                // oid 0 is a correct and standard way to produce undefined.
                return (val === void 0) || (typeof val === 'undefined') && (Object.prototype.toString.call(val) === '[object Undefined]');
            },
            /**
             * 判断一个变量是不是为空
             * @param val
             * @returns {boolean}
             */
            isNull: function (val) {
                return (val === null) && (Object.prototype.toString.call(val) === '[object Null]');
            },
            /**
             * 检测
             * @param obj
             * @returns {*}
             */
            isNaN: function (val) {
                // 只要这个数字通过判断是不是和他自身相同或者使用typef的方式去检测
                return val !== val;
            },
            /**
             * 判断一个变量是不是一个对象类型
             * @param val
             * @returns {boolean}
             */
            isObject: function (val) {
                if (val !== null && val !== undefined) {
                    if ((typeof val === 'object') && (Object.prototype.toString.call(val))) {
                        return true;
                    }
                }
                return false;
            },
            /**
             * 判断一个对象是不是数组对象
             * @param val
             * @returns {boolean|void|string}
             */
            isArray: function (val) {
                // 判断上不是一个数组的先判断这个数组对象是不是为空, 因为如果val为空的话,就是val.constructor这个属性实际上是没有的,error
                if (val !== null || typeof val !== "undefined") {
                    // 注意在使用constructor判断数据类型的时候比较的实际上是他的原型对象的constructor属性, 这个属性指向的实际上是这个变量的原型对象
                    return (val.constructor === Array) && (Object.prototype.toString.call(val) === '[object Array]');
                }
                return false;
            }

        });
    }


    //  调用函数,实现生效
    api.isNeedChainedAccess();
    api.isNotNeedChainedAccess();

    return api;
});

stringModule.js

/**
 * @Desc : 主要的功能模块展示
 * @Author : xiugang
 * @Time : 20180722
 */
/**
 *  这个模块是用来出来原型对象的方法扩展的,主要用于实现一个String,Array,Function等内置函数方法的扩展
 */
define(function () {

    // 定义一个关于字符串处理的API接口
    var api = {
    }


    api.isNeedChainedAccess = function(){

    }
    api.isNotNeedChainedAccess = function(){
        // str = 'name: @(name), age:@(age)'
        // data = {name : 'xiugang', age : 18}
        /**
         * 实现一个简单的数据绑定
         * @param str
         * @param data
         * @return {*}
         */
        String.prototype.formateString = function (data) {
            return this.replace(/@\((\w+)\)/g, function (match, key) {
                // 注意这里找到的值必须返回出去(如果是undefined,就是没有数据)
                // 注意:判断一个值的类型是不是undefined,可以通过typeof判断
                console.log(typeof data[key] === 'undefined');
                return data[key] === 'undefined' ? '' : data[key];
            });

        }
        /**
         * 去掉坐标的空格
         * @param str
         * @return {*}
         */
        String.prototype.ltrim = function () {
            return this.replace(/^\s*/g, '');

        }
        /**
         * 去掉右边的空格
         * @param str
         * @return {*}
         */
        String.prototype.rtrim = function () {
            return this.replace(/\s*$/g, '');
        }
        /**
         * 去掉两边的空格
         * @param str
         * @return {*}
         */
        String.prototype.trim = function () {
            return this.replace(/(^\s*)|(\s*$)/g, '');
        }

        // red===>Red
        /**
         * 将第一个字母小写,其他字母大写
         * @param str
         * @return {*}
         */
        String.prototype.camelCase = function () {
            // .*?是非贪婪的匹配,点可以匹配任意字符,星号是前边的字符有0-n个均匹配,问号是则是0-1;
            // (^\w{1}): 用于匹配第一个首字母
            // (.*):用于匹配任意个的前面的字符

            // - param 1: 匹配到的字符串
            // - param 2: 匹配的的子字符串
            // - param 3: 匹配的子字符串
            // - param 4: 匹配到的字符串在字符串中的位置
            // - param 5: 原始字符串

            return this.replace(/(^\w{1})(.*)/g, function (match, g1, g2) {
                return g1.toUpperCase() + g2.toLowerCase();
            });
        }
        /**
         * @param 作用是将连字符类的css属性值,转换成驼峰写法。
         * 将background-color转换为backgroundColor
         */
        String.prototype.camelize = function(){
            //  \w 表示 匹配包括下划线的任何单词字符
            return this.replace(/-(\w)/g, function (strMatch, p1){
                return p1.toUpperCase();
            });
        }

        /**
         * 将一个字符串的下划线转换为中划线
         * @param str
         * @return {*}
         */
        String.prototype.dashString = function () {
            // 这里面的this实际上指向的就是我们自己定义的一个变量字符串
            return this.replace(/\_/g, '-');
        }

        /**
         * 检测一个字符串是不是为空
         * @return {boolean}
         */
        String.prototype.isEmpty = function () {
            return this.length === 0;

        }
        /**
         * 判断字符串是不是包含一个字符串
         * @param target
         * @return {boolean}
         */
        String.prototype.contains = function (target) {
            // 只要这个indexOf的下标不是-1的话,就说明包含这个目标字符串,否则的话就是不包含
            // indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置,如果没找到的话,就返回-1
            return this.indexOf(target) !== -1;
        }
        /**
         * 对一个字符串中的特殊字符进行转义
         * @return {string}
         */
        String.prototype.escapeHTML = function () {
            /*显示结果	描述	实体名称	实体编号
                        空格	&nbsp;	&#160;
                        <	小于号	&lt;	&#60;
                        >	大于号	&gt;	&#62;
                        &	和号	&amp;	&#38;
                        "	引号	&quot;	&#34;
                        '	撇号 	&apos; (IE不支持)	&#39;
                        ¢	分	&cent;	&#162;
                        �0�5	镑	&pound;	&#163;
                        �0�6	日圆	&yen;	&#165;
                        €	欧元	&euro
            * **/


            // 先进行字符串分割, 得到一个数组
            var strArr = this.split('');
            for (var pos = 0, l = strArr.length, tmp; pos < l; pos++) {
                // 拿到数组中的每一个元素
                tmp = strArr[pos];
                // 对字符串中的每一个元素进行判断, 如果是特殊字符的话就进行处理
                switch (tmp) {
                    // pos始终为1, 表示要替换的项是1项
                    case '<':
                        replaceArr(strArr, pos, '&lt;');
                        break;
                    case '>':
                        replaceArr(strArr, pos, '&gt;');
                        break;
                    case '\'':
                        replaceArr(strArr, pos, '&#39;');
                        break;
                    case '\"':
                        replaceArr(strArr, pos, '&quot;');
                        break;
                    case '&':
                        replaceArr(strArr, pos, '&amp;');
                        break;
                    default:
                        ;
                }
            }
            // join() 方法用于把数组中的所有元素放入一个字符串。
            return strArr.join('');

            // 专门用于替换掉数组中的元素
            /**
             * 替换数组中指定的项
             * @param arr
             * @param pos
             * @param item
             * @return {*}
             */
            function replaceArr(arr, pos, item) {
                // Splice: splice主要用来对JS中的数组进行操作,包括删除,添加,替换等,原来的数组会被改变
                // 删除数据:array.splice(index,num),返回值为删除内容,array为结果值。index为起始项,num为删除元素的的个数。
                // 插入数据:array.splice(index,0,insertValue),index要插入的位置,insertValue要插入的项
                // 替换数据:array.splice(index,num,insertValue),index起始位置,num要被替换的项数,insertValue要替换的值
                return arr.splice(pos, 1, item);
            }

        }
        /**
         * 忽略HTML中的一些内置的特殊字符
         * @return {string}
         */
        String.prototype.escapeHTML = function () {
            return Array.prototype.slice.call(this).join('').replace(/$/g, '&amp')
                .
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值