23年,我又学习了一次amd模块化,模块化思想
项目目录src
view1
index.html
main.js
view2
plugins
module.js
jquery.js
......
modules // amd模块文件
a1.js
b1.js
c.js
b2.js
b21.jssrc/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>
</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) === false) {
break;
}
}
},
// 只保留指定的keys
inKeys(target, keys) {
return Object.keys(target).reduce((newData, key) => {
if (keys.includes(key)) {
newData = target;
}
return newData;
}, {});
},
// 路径拼接
pathJoin(...paths){
let path = '';
for(let i = paths.length - 1; i > -1; i--) {
let pathItem = paths.replace(/\/+$/, '');
// 如果是绝对路径
if(/^\//.test(pathItem)) {
path = pathItem + '/'+ path;
break;
}
// 如果是相对路径
if(/^\.\//.test(pathItem)) {
pathItem = pathItem.slice(2)
}
// 如果是: ../../a/b/c
if(/^(\.{2}\/)+\S+/.test(pathItem) && paths) {
let matches = null;
while(matches = /^\.{2}\/(\S+)/.exec(pathItem)) {
pathItem = matches;
let prevPath = paths.replace(/\/+$/, '');
if(prevPath) {
paths = 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.deps;
var done = true;
utils.each(deps, function(moduleName) {
var dep = depsTree;
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;
if(event){
for(let i = 0; i < event.length; i++){
event.apply(this, data);
}
}
return this;
}
,$on:function(event,handle){
let subEvents = this.subEvents;
!(event in subEvents) && (subEvents = [])
subEvents.push(handle);
return this;
}
,$off:function(event,handle){
let events = this.subEvents;
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;
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;
},
set: function(value) {
if(ctx !== value) {
ctx = 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) {
this.deps = {
moduleName,
deps,
factory
};
}
},
// 核心方法
// 迭代收集每一个入口依赖
traverseDeps(deps, callback){
var _self = this;
function buildDepsRelation(moduleName, depsTree) {
var oldDepsTree = depsTree;
var module = _self.deps;
depsTree = depsTree || { entry: moduleName };
depsTree = 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', )
buildDepsRelation(moduleName, depsTree);
}
document.body.appendChild(script);
}else {
let curModuleName = moduleName;
// 1,依赖已加载完成
if(_self.deps) {
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;
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 = );
// 迭代收集每一个入口依赖
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
来源:https://www.cnblogs.com/littleboyck/p/amd.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页:
[1]