一步一步DIY jQuery库2-使用es6模块化

来源:互联网 发布:js手写bind实现原理 编辑:程序博客网 时间:2024/06/05 21:18

本博文使用了rollup打包,这里同时提供了简明的搭建环境的说明,通过第一部分1.环境搭建就可以在本地配置搭建环境。有关rollup的详细安装使用说明可以查看我的另外一篇博客:《rollup + es6最佳实践》

我们首先把《一步一步DIY一个自己jQuery库1》的代码使用es6模块化的方式打包好

【注】所有代码挂在我的github上

1.搭建环境

1.1 目录结构

  - src    + .babelrc    + core.js    + global.js    + init.js    + jquery.js    + util.js  bundle.js  package.json  rollup.config.dev.js  test.html
  • src是源代码文件夹,其中jquery.js是入口文件
  • bundle是编译后的文件
  • package.json是包管理文件
  • rollup.config.dev.js是rollup的配置文件
  • test.html是测试文件,引入<script src="bundle.js"></script>即可测试

1.2 npm安装

npm i rollup rollup-plugin-babel babel-preset-es2015-rollup --save-dev

1.3 使用配置编译

新建文件,文件名为rollup.config.dev.js

import babel from 'rollup-plugin-babel';export default {  entry: 'src/jquery.js',  format: 'umd',  moduleName: 'jQuery',  plugins: [babel() ],  dest: 'bundle.js',};

src中.babelrc

{  presets: [    ["es2015", { "modules": false }]  ]}

注意{ "modules": false }一定要有,否则一直报错
执行命令:rollup -c rollup.config.dev.js,就能得到编译后的文件bundle.js。这里使用的是【umd】的形式,这是jquery的发布版本的格式,当然还有其他的一些格式,amd / es6 / cjs / iife

2.打包

jquery.js

// 出口import jQuery from './core';import global from './global';import init from './init';global(jQuery);init(jQuery);export default jQuery;

core.js

var version = "0.0.1",    jQuery = function(selector, context) {        return new jQuery.fn.init(selector, context);    };jQuery.fn = jQuery.prototype = {    jquery: version,    constructor: jQuery,    setBackground: function() {        this[0].style.background = 'yellow';        return this;    },    setColor: function() {        this[0].style.color = 'blue';        return this;    }};jQuery.extend = jQuery.fn.extend = function() {    var isObject = function(obj) {        return Object.prototype.toString.call(obj) === "[object Object]";    };    var isArray = function(obj) {        return Object.prototype.toString.call(obj) === "[object Array]";    };    var name, clone, copy, copyIsArray ,options, i = 1,        length = arguments.length,        target = arguments[0] || {},        deep = false; //默认为浅复制    if (typeof target === "boolean") {        deep = target;        target = arguments[i] || {};        i++;    }    if (typeof target !== "object" && typeof target !== "function") {        target = {};    }    //target后面没有其他参数了(要拷贝的对象),直接扩展jQuery自身,target并入jQuery    if (i === length) {        target = this;        i--;    }    for (; i < length; i++) {        if ((options = arguments[i]) != null) {            for (name in options) {                src = target[name]; //jQuery是否已经有该属性                copy = options[name];                if (target === copy) {                    continue;                }                //深拷贝,且确保被拷属性为对象/数组                if (deep && copy && isObject(copy) || (copyIsArray = isArray(copy))) {                    //被拷贝属性为数组                    if (copyIsArray) {                        copyIsArray = false;                        //被合并属性                        clone = src && isArray(src) ? src : [];                    } else { //被拷贝属性为对象                        clone = src && isObject(src) ? src : {};                    }                    //右侧递归,直到内部属性值是非对象                    target[name] = jQuery.extend(deep, clone, copy);                } else if (copy !== undefined) { //非对象/数组,或者浅复制的情况                    target[name] = copy; //递归结束                }            }        }    }    //返回修改后的target    return target;};export default jQuery;

init.js

var init = function(jQuery){    jQuery.fn.init = function (selector, context, root) {        if (!selector) {            return this;        } else {            var elem = document.querySelector(selector);            if (elem) {                this[0] = elem;                this.length = 1;            }            return this;        }    };    jQuery.fn.init.prototype = jQuery.fn;};export default init;

global.js

var global = function(jQuery){    //走模块化形式的直接绕过    if(typeof exports === 'object'&&typeof module !== 'undefined') return;    var _jQuery = window.jQuery,        _$ = window.$;     jQuery.noConflict = function( deep ) {        //确保window.$没有再次被改写        if ( window.$ === jQuery ) {            window.$ = _$;        }        //确保window.jQuery没有再次被改写        if ( deep&&window.jQuery === jQuery ) {            window.jQuery = _jQuery;        }        return jQuery;  //返回 jQuery 接口引用    };    window.jQuery = window.$ = jQuery;};export default global;

打包后bundle.js

(function (global, factory) {    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :    typeof define === 'function' && define.amd ? define(factory) :    (global.jQuery = factory());}(this, (function () { 'use strict';var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };var version = "0.0.1";var jQuery$1 = function jQuery$1(selector, context) {    return new jQuery$1.fn.init(selector, context);};jQuery$1.fn = jQuery$1.prototype = {    jquery: version,    constructor: jQuery$1,    setBackground: function setBackground() {        this[0].style.background = 'yellow';        return this;    },    setColor: function setColor() {        this[0].style.color = 'blue';        return this;    }};jQuery$1.extend = jQuery$1.fn.extend = function () {    var isObject = function isObject(obj) {        return Object.prototype.toString.call(obj) === "[object Object]";    };    var isArray = function isArray(obj) {        return Object.prototype.toString.call(obj) === "[object Array]";    };    var name, clone, copy, copyIsArray, options,        i = 1,        length = arguments.length,        target = arguments[0] || {},        deep = false; //默认为浅复制    if (typeof target === "boolean") {        deep = target;        target = arguments[i] || {};        i++;    }    if ((typeof target === 'undefined' ? 'undefined' : _typeof(target)) !== "object" && typeof target !== "function") {        target = {};    }    //target后面没有其他参数了(要拷贝的对象),直接扩展jQuery自身,target并入jQuery    if (i === length) {        target = this;        i--;    }    for (; i < length; i++) {        if ((options = arguments[i]) != null) {            var name, clone, copy;            for (name in options) {                src = target[name]; //jQuery是否已经有该属性                copy = options[name];                if (target === copy) {                    continue;                }                //深拷贝,且确保被拷属性为对象/数组                if (deep && copy && isObject(copy) || (copyIsArray = isArray(copy))) {                    //被拷贝属性为数组                    if (copyIsArray) {                        copyIsArray = false;                        //被合并属性                        clone = src && isArray(src) ? src : [];                    } else {                        //被拷贝属性为对象                        clone = src && isObject(src) ? src : {};                    }                    //右侧递归,直到内部属性值是非对象                    target[name] = jQuery$1.extend(deep, clone, copy);                } else if (copy !== undefined) {                    //非对象/数组,或者浅复制的情况                    target[name] = copy; //递归结束                }            }        }    }    //返回修改后的target    return target;};var _typeof$1 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };var global = function global(jQuery) {    //走模块化形式的直接绕过    if ((typeof exports === 'undefined' ? 'undefined' : _typeof$1(exports)) === 'object' && typeof module !== 'undefined') return;    var _jQuery = window.jQuery,        _$ = window.$;    jQuery.noConflict = function (deep) {        //确保window.$没有再次被改写        if (window.$ === jQuery) {            window.$ = _$;        }        //确保window.jQuery没有再次被改写        if (deep && window.jQuery === jQuery) {            window.jQuery = _jQuery;        }        return jQuery; //返回 jQuery 接口引用    };    window.jQuery = window.$ = jQuery;};var init = function init(jQuery) {    jQuery.fn.init = function (selector, context, root) {        if (!selector) {            return this;        } else {            var elem = document.querySelector(selector);            if (elem) {                this[0] = elem;                this.length = 1;            }            return this;        }    };    jQuery.fn.init.prototype = jQuery.fn;};// 出口global(jQuery$1);init(jQuery$1);return jQuery$1;})));

3.增加基础工具模块&完善extend方法

我们在《一步一步DIY一个自己jQuery库1》中说过extend方法的不完善的地方
- 使用isObject,isArray并不严谨。在某些浏览器中,像 document 在 Object.toSting 调用时也会返回和 Object 相同结果;

新增一个util.js

export var class2type = {}; //在core.js中会被赋予各类型属性值export const toString = class2type.toString; //等同于 Object.prototype.toStringexport const getProto = Object.getPrototypeOf;export const hasOwn = class2type.hasOwnProperty;export const fnToString = hasOwn.toString; //等同于 Object.toString/Function.toStringexport const ObjectFunctionString = fnToString.call(Object); //顶层Object构造函数字符串"function Object() { [native code] }",用于判断 plainObj

core.js中修改/新增代码
- 导入

import { class2type, toString, getProto, hasOwn, fnToString, ObjectFunctionString } from './util.js';
  • 修改
typeof target !== "function"   //修改为!jQuery.isFunction(target)isArray                        //均修改为jQuery.isArrayisObject                       //均修改为jQuery.isObject
  • 新增
//新增修改点1,class2type注入各JS类型键值对,配合 jQuery.type 使用,后面会用上"Boolean Number String Function Array Date RegExp Object Error Symbol".split(" ").forEach(function(name) {    class2type["[object " + name + "]"] = name.toLowerCase();});//新增修改点2jQuery.extend({    isArray: Array.isArray || function( obj ) {        return jQuery.type(obj) === "array";    },    isFunction: function( obj ) {        return jQuery.type(obj) === "function";    },    isPainObject: function(obj) {        var proto, Ctor;        if (!obj || toString.call(obj) !== "[object Object]") {            return false;        }        proto = getProto(obj);        // 通过 Object.create( null ) 形式创建的 {} 是没有prototype的        if (!proto) {            return true;        }        //简单对象的构造函数等于最顶层Object构造        Ctor = hasOwn.call(proto, "constructor") && proto.constructor;        return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;    },    type: function(obj) {        if (obj == null) { //不能用 ===             return obj + ""; //undefined or null        }        return typeof obj === "object" || typeof obj === "function" ?            //兼容安卓2.3- 函数表达式类型不正确情况            class2type[toString.call(obj)] || "object" :            typeof obj;    }});

修改后的文件我已经挂在了我的github中,对应文件夹是v2.

参考阅读:
- 从零开始,DIY一个jQuery(1)
- 从零开始,DIY一个jQuery(2)
- 从零开始,DIY一个jQuery(3)

0 0