23年,我又学习了一次amd模块化,模块化思想

  • 23年,我又学习了一次amd模块化,模块化思想已关闭评论
  • 172 次浏览
  • A+
所属分类:Web前端
摘要

src/view1/index.htmlsrc/view1/main.jsplugins/module.js源码链接: https://gitee.com/littleboyck/front/tree/master/front-module

    项目目录       src         view1           index.html           main.js         view2       plugins         module.js         jquery.js         ......       modules // amd模块文件          a1.js         b1.js         c.js         b2.js         b21.js

src/view1/index.html

<!DOCTYPE html>     <html lang="en">     <head>         <meta charset="UTF-8">         <meta http-equiv="X-UA-Compatible" content="IE=edge">         <meta name="viewport" content="width=device-width, initial-scale=1.0">         <title>Document</title>     </head>     <body>         <!-- 引入amd插件-->         <!-- amd都有一个入口文件,我这里设计的方式是:自动引入同级目录下的main.js-->               <script src="/plugins/module.js"></script>     </body>     </html>

src/view1/main.js

module .configs({     baseUrl: '../modules' }) .require(['a1','a2'], function(a2) {     console.log('a2: ', a2) })

plugins/module.js

    // 使用IIFE     (function(win){         function module(){             this.context = {                 baseUrl: './',                 alias: {},                 entry: 'main.js',                 suffix: '.js',             }             this.deps = {};             this.srcs = [];             this.customEvt = new module.CustomEvt();             this.ready();         }          var utils = module.utils = {             each(arr, callback){                 var keys = Object.keys(arr);                 for(var i = 0; i < keys.length; i++) {                      if(callback.call(arr, arr[i], i) === false) {                         break;                     }                 }             },             // 只保留指定的keys             inKeys(target, keys) {                 return Object.keys(target).reduce((newData, key) => {                     if (keys.includes(key)) {                         newData[key] = target[key];                     }                     return newData;                 }, {});             },             // 路径拼接             pathJoin(...paths){                 let path = '';                 for(let i = paths.length - 1; i > -1; i--) {                     let pathItem = paths[i].replace(//+$/, '');                     // 如果是绝对路径                     if(/^//.test(pathItem)) {                         path = pathItem + '/'+ path;                         break;                     }                     // 如果是相对路径                     if(/^.//.test(pathItem)) {                         pathItem = pathItem.slice(2)                     }                     // 如果是: ../../a/b/c                     if(/^(.{2}/)+S+/.test(pathItem) && paths[i-1]) {                         let matches = null;                         while(matches = /^.{2}/(S+)/.exec(pathItem)) {                             pathItem = matches[1];                             let prevPath = paths[i-1].replace(//+$/, '');                             if(prevPath) {                                 paths[i-1] = prevPath.slice(0, prevPath.lastIndexOf('/'))                             }                         }                     }                     path = pathItem + '/'+ path;                 }                 return path.replace(//+$/, '');             },             createScript(src) {                 var node = document.createElement('script');                 node.type = 'text/javascript';                 node.async = true;                 node.src = src;                 return node;             },             // 判断所有依赖是否加载完成             isDepsDone(options) {                 var { depsTree, entry = depsTree.entry, deps } = options;                 var deps = deps || depsTree[entry].deps;                 var done = true;                 utils.each(deps, function(moduleName) {                     var dep = depsTree[moduleName];                     if(dep) {                         if(dep.deps.length > 0) {                             done = utils.isDepsDone({                                 depsTree,                                 entry,                                 deps: dep.deps                             });                             if(!done) {                                 return false;                             }                         }                     }else {                         done = false;                         return false;                     }                 });                 return done;             }         }          var CustomEvt = function(){             this.subEvents = {};         };          CustomEvt.prototype = {             constructor:CustomEvt             ,$emit:function(event,data){                 event = this.subEvents[event];                 if(event){                     for(let i = 0; i < event.length; i++){                         event[i].apply(this, data);                     }                 }                 return this;             }             ,$on:function(event,handle){                 let subEvents = this.subEvents;                 !(event in subEvents) && (subEvents[event] = [])                 subEvents[event].push(handle);                 return this;             }             ,$off:function(event,handle){                 let events = this.subEvents[event];                 if(!handle){                     events && Reflect.deleteProperty(this.subEvents, event);                 }else{                     if(typeof handle == 'function' && events){                         for(let i = 0,len = events.length; i < len; i++){                             let event = events[i];                             if(event == handle){                                 return events.splice(i,1);                             }                         }                      }                 }                 return this;             }         }          module.CustomEvt = CustomEvt;          // // 主题对象         // function Subject() {         //     this.observers = [];         // }         // // 添加观察者         // Subject.prototype.addObserver = function(observer) {         //    !this.observers.includes(observer) && this.addObserver.push(observer);         // }         // Subject.prototype.notify = function(message) {         //     this.observers.forEach(observer => {         //         observer.update(message);//观察者接收消息的方法         //     })         // }         // function Observer() {}         // Observer.prototype.update = function(message) {         // }          Object.assign( module.prototype, {             // 入口函数             ready() {                 this.setCtxProxy();                 // 这里默认加载同级目录下的main.js,请确保main.js的存在                 var script = utils.createScript(this.getUrl('./', this.entry));                 document.body.appendChild(script);             },             // 设置context对象的属性,通过代理访问             setCtxProxy(){                 var _self = this;                 var ctx = this.context;                 utils.each(Object.keys(ctx), function(key) {                     Object.defineProperty(_self, key, {                         get: function() {                             return ctx[key];                         },                         set: function(value) {                             if(ctx[key] !== value) {                                 ctx[key] = value;                                 return true;                             }                         }                     })                 });             },             configs(options) {                 Object.assign(this.context, utils.inKeys(options, ['baseUrl', 'alias', 'entry']))                 return this;             },             getUrl(baseUrl, moduleName) {                 var path = utils.pathJoin(baseUrl, moduleName);                 return new RegExp('\'+this.suffix+'$').test(path) ? path : path + this.suffix;             },             // 核心方法:define,收集依赖             define(moduleName, deps, factory) {                 typeof deps == 'function' && (                     factory = deps,                     deps = []                 )                 if(!this.deps[moduleName]) {                     this.deps[moduleName] = {                         moduleName,                         deps,                         factory                     };                 }             },             // 核心方法             // 迭代收集每一个入口依赖             traverseDeps(deps, callback){                 var _self = this;                  function buildDepsRelation(moduleName, depsTree) {                     var oldDepsTree = depsTree;                     var module = _self.deps[moduleName];                     depsTree = depsTree || { entry: moduleName };                     depsTree[moduleName] = module;                     if(module.deps.length > 0) {                         traverseScript(module.deps, depsTree);                     }else {                         // 所有依赖收集完,才返回                         if(utils.isDepsDone({ depsTree })) {                             typeof callback == 'function' && callback(depsTree);                         }                     }                     // 表示是第一层的递归,只重置第一层的递归                     if(!oldDepsTree) {                         depsTree = null;                     }                 }                  function traverseScript(deps, depsTree) {                     utils.each(deps, function(moduleName, i) {                         var curSrc = _self.getUrl(_self.baseUrl, moduleName);                         var isExistSrc = _self.srcs.includes(curSrc);                         // 判断相同的依赖是否已经加载过                         if(!isExistSrc) {                             _self.srcs.push(curSrc);                             var script = utils.createScript(curSrc);                             script.onload = function() {                                 _self.customEvt.$emit('scriptLoaded', [moduleName])                                 buildDepsRelation(moduleName, depsTree);                             }                             document.body.appendChild(script);                         }else {                             let curModuleName = moduleName;                             // 1,依赖已加载完成                             if(_self.deps[curModuleName]) {                                 buildDepsRelation(moduleName, depsTree);                             }else {                                 // 2,scriptLoad加载完成后,this.deps才有值                                 _self.customEvt.$on('scriptLoaded', function(moduleName) {                                     if(moduleName == curModuleName) {                                         buildDepsRelation(moduleName, depsTree);                                     }                                 });                             }                         }                     })                 }                  traverseScript(deps)             },             // 一次收集全部依赖树的依赖             getAllDeps(initDeps, callback) {                 var _self = this;                 function traverseDeps(deps) {                     utils.each(deps, function(moduleName) {                         var curSrc = _self.getUrl(_self.baseUrl, moduleName);                         var isExistSrc = _self.srcs.includes(curSrc);                         // 判断相同的依赖是否已经加载过                         if(!isExistSrc) {                             _self.srcs.push(curSrc);                             var script = utils.createScript(curSrc);                             script.onload = function() {                                 var module = _self.deps[moduleName];                                 if(module.deps.length > 0) {                                     traverseDeps(module.deps);                                 }else {                                     // 所有依赖收集完,才返回                                     var isDone = initDeps                                     .map(entryDep => utils.isDepsDone({ depsTree: _self.deps, entry: entryDep }))                                     .every(isDone => isDone === true);                                     if(isDone){                                         typeof callback == 'function' && callback(_self.deps);                                     }                                 }                             }                             document.body.appendChild(script);                         }else {                             // 所有依赖收集完,才返回                             var isDone = initDeps                             .map(entryDep => utils.isDepsDone({ depsTree: _self.deps, entry: entryDep }))                             .every(isDone => isDone === true);                             if(isDone){                                 typeof callback == 'function' && callback(_self.deps);                             }                         }                     })                 }                 traverseDeps(initDeps)             },             require(deps, factory) {                 typeof deps == 'string' && (deps = [deps]);                 // 迭代收集每一个入口依赖                 this.traverseDeps(deps, function(depsTree) {                     console.log(depsTree);                 });                  // 一次性收集所有依赖                 // this.getAllDeps(deps, function(alldeps) {                 //     console.log(alldeps)                 // })             }         });         win.module = new module();     })(this);

源码链接: https://gitee.com/littleboyck/front/tree/master/front-module

联系方式:QQ: 1187253007