文章目录
# why ?
不同功能封装成独立的文件
只开放部分功能性接口
代码复用
避免命名冲突
解耦(可管理)
# 开发模块管理引擎
市场上的 模块管理引擎:
AMD require.js
CMD sea.js
COMMONJS NODE.js
UMD
## (手写) 简单的 模块管理
moduleList
- 容器、管理模块define
- 定义模块@param {String[]} modules
依赖模块
let module = (function() {
const moduleList = {} ; // 容器
/** * @description 模块管理 * @param {String} name 名字 * @param {String[]} modules 依赖的模块 * @param {Function} action 执行的方法 * @return 开放接口 */
function define(name, modules, action) { // 初始化
modules.forEach((m,i)=> {
modules[i] = moduleList[m]
});
moduleList[name] = action.apply(null,modules) ;// 往容器里面压模块
}
return {define} ;
})();
module.define('hd', [], function() { // 导出
return {
first(arr) {
return arr[0] ;
},
max(arr, key) {
return arr.sort((a, b) => b[key]-a[key])[0];
}
};
})
module.define('lesson', ['hd'], function(hd) { // 导入
let data = [
{name:'js', price: 99, click: 4} ,
{name:'mysql', price: 222, click: 2} ,
{name:'vue.js', price: 300, click: 3} ,
]
let max = hd.max(data, 'price') ;
console.log(max)
})
# 使用:export / import … from …
通过 以下命令,就实现了 模块的 定义、导出、导入
module.js 文件
export 指定 导出哪些接口
let title = '后盾热' ;
let url = 'www.baidu.com'
export {title}
.html 文件
import 指定 导入哪些接口
from 指定从那里导入 (必须指定明确的路径,否则不能识别。只有到了用打包工具的时候,打包工具才能比较智能的识别)
<script type="module"> import {title} from './module.js' ; console.log(title) </script>
注意:
script 标签需要 加上type='module'
<script type="module"> ... </script>
# 模块的延时加载
只要 script 加了 type=‘module’
那么这个标签就是延时加载的
即便脚本放在了body上面,仍然能找到body 内容(看下面)
let a = document.querySelector('button') ;
console.log('module' , a) ;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="module"> let a = document.querySelector('button') ; console.log('html' , a) ; import {} from "./module.js" </script>
<body>
<button>后盾人</button>
</body>
</html>
# 默认是 严格模式
模块默认是 严格模式 'use strict'
<script type="module"> site = 'aa' // 非严格模式下,是不报错的 </script>
# 模块的 作用域
非模块标签内的变量是定义在全局的(下图)
模块标签的作用只在模块标签内部(下图)
# 模块的(预解析)的必要性
模块的导入,只有在 第一次
导入的时候才会解析数据。
避免了重复初始化
(下图)
<script type="module"> import {} from "./module.js" ; import {} from "./module.js" ; import {} from "./module.js" ; import {} from "./module.js" ; import {} from "./module.js" ; </script>
module.js
class Common {
init() {
console.log("初始化")
}
}
new Common().init() ;
同样的,如皋导入的模块导入已导入的模块,也不会再次出发编译(绕?就对了)
(下图)
<script type="module"> import {} from "./module.js" ; import {} from "./module1.js" ; </script>
module.js
class Common {
init() {
console.log("初始化")
}
}
new Common().init() ;
module1.js
import {} from "./module.js" ; // 导入 上面模块
console.log('module-1')
(下图)可以看到,module.js 模块只初始化一次
# 具名导出、导入
具名导入(具体名字导入)
直接在属性、方法前加 export 导出
或者 在最后具名导出
也是能用的
# 批量导入与建议
<script type="module">
import * as api from "./module.js" ;
console.log(api)
</script>
let site = 'www.baidu.com' ;
function show() {
console.log('show')
}
class Common {
init() {
console.log("初始化")
}
}
new Common().init() ;
export {site, show , Common}
建议:
使用具名导入
- 导入体积小
- 代码清晰
# 别名
<script type="module"> import {site as s} from "./module.js" ; // 导入时候别名 let site = 'www.bilibili.com' ; console.log(s) </script>
let site = 'www.baidu.com' ;
function show() {
console.log('show')
}
class Common {
init() {
console.log("初始化")
}
}
new Common().init() ;
export {site, show as s , Common} // 导出时候别名
# 默认导出 default
默认导出,import 就不用加花括号 {...}
了
<mark>但是,只能有一个</mark>
<script type="module"> import s from "./module.js" ; // 或者 import {default as s, site } from "./module.js" // 或者 import s , {site} from "./module.js" ; s() </script>
导出可以是(下图)
let site = 'www.baidu.com' ;
function show() {
console.log('show')
}
class Common {
init() {
console.log("初始化")
}
}
new Common().init() ;
export {site, show as default , Common} // 默认导出 show
也可以是(下图)
let site = 'www.baidu.com' ;
export default function show() { // 默认导出 show
console.log('show')
}
class Common {
init() {
console.log("初始化")
}
}
new Common().init() ;
export {site, show , Common}
坑
如果批量导出 , 用 default 的 默认导出 需要这样调用(下图)
# 规范 - 推荐
导出 名尽量和 文件名 相关
# 模块合并导出
为了管理方便,弄一个专门的模块作为入口
管理其他模块
m13.2.js
let url = 'www.baidu.com-2'
function show() {
console.log(url) ;
}
class User {
}
export {url, show, User as default}
m13.1.js
let url = 'www.baidu.com-1'
function show() {
console.log(url) ;
}
class User {
}
export {url, show, User as default}
m13.index.js
import * as m131 from "./m13.1.js"
import * as m132 from "./m13.2.js"
export{ m131, m132}
<script type="module"> import * as api from "./m13.index.js" ; api.m131.show() ; api.m132.show() ; console.log(api.m131.default) console.log(api) </script>
# 按需动态加载 - import()、Promise 对象
之前 import ... from ...
的模式 , 必须在顶层
否则报错(下图)
## Promise 对象
ES6 标准
import() 函数 返回一个 Promise 对象
Promise 对象有个 then 方法,当模块加载完成,进行回调
(如下)
./m13.1.js
let url = 'www.baidu.com-1'
function show() {
console.log(url) ;
}
class User {
}
export {url, show, User as default}
使用 import
import('./m13.1.js').then(module => {
console.log(module)
})
接收的 module 对象就是 模块对象
## 按需加载 【实现】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>点击,后加载</button>
</body>
<script type="module"> document.querySelector('button') .addEventListener('click',() => { import('./m13.1.js').then(({url, site}) => { console.log(site,url) }); }) </script>
</html>
m13.1.js 模块
console.log("按需加载")
let site = 'www.baidu.com'
let url = 'www.bilibili.com'
export {site,url}