模塊無非就是把一些通用的定義成文件.
起到復(fù)用,結(jié)構(gòu)層次清晰,后期好維護(hù)等好處.
不管是什么 CommonJS , AMD 還是 CMD.
最主要的就是要先摸清三個(gè)事情.
- 如何定義模塊?
- 如何使用模塊?
- 這些模塊的代碼是在哪里跑的?
CommonJS
Node.js 實(shí)現(xiàn)了 CommonJS 的模塊化規(guī)范.(跑在后臺服務(wù)器的)
CommonJs 提供了四個(gè)環(huán)境變量,為模塊化提供了支持.(模塊是怎么定義以及怎么使用的)
module
expors
require
global
實(shí)際使用時(shí)
- 使用
require
來導(dǎo)入你需要使用到的模塊. - 使用
exports.xxx
或者moudle.exports
帶導(dǎo)出當(dāng)前模塊輸出的接口.
一般推薦使用 module.export = {} 的方式.而非 exports.xxx
// 定義 math.js 模塊.
function plus(num1,num2) {
return num1 + num2
}
// exports.plus = plus 不推薦這種寫法.
module.exports = {
plus
}
// 使用 math.js 模塊
// main.js
const math = require('./math')
math.plus(1,2)
CommonJs 使用同步的方式加載模塊.
模塊執(zhí)行的環(huán)境在本地的服務(wù)器的Node環(huán)境中.
一切都是這么的和諧自然.
一般后端開發(fā)語言都包含模塊.
比如:
- java 的 import
- c# 的 using
- Node 的 require
AMD & RequireJS
AMD 全稱是 Asynchronous Module Definition
.
AMD 模塊是跑在瀏覽器環(huán)境中的.(跑在前端瀏覽器中的)
AMD 規(guī)范采用了異步的方式加載模塊,模塊的加載不影響它后續(xù)的語句執(zhí)行.
所以依賴這個(gè)模塊的語句,都定義在后面的那個(gè)回調(diào)函數(shù)中.
并以參數(shù)的形式提供.
等到所有依賴的模塊都加載完畢之后,這個(gè)回調(diào)函數(shù)才會執(zhí)行.
它是瀏覽器端的一種模塊化異步加載的規(guī)范.
requireJS
實(shí)現(xiàn)了 AMD
的這套標(biāo)準(zhǔn).
使用 requireJS
提供的幾個(gè)簡單的 API 接口,就可以讓我們實(shí)現(xiàn)前端模塊化的開發(fā).(模塊怎么定義以及怎么使用的.)
- 使用 requireJS 提供的
define()
來定義模塊. - 使用 requireJS 提供的
require()
來使用模塊.
當(dāng)然,這里的前端化組件開發(fā),肯定就是不之間的那種多個(gè)
<script></script>
按順序?qū)氲哪欠N情況了.
AMD 實(shí)際會根據(jù) define() 或者 require() 中依賴的模塊內(nèi)容,異步的加載對應(yīng)的js文件.
step 1
首先要去 requireJS
官網(wǎng)下載 requirejS 文件.
step 2
新建一個(gè) index.html
,并導(dǎo)入我們下載好的這個(gè) requireJS
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>AMD-Asynchronous Module Definition</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
<!-- 導(dǎo)入 require.js -->
<script src="./js/require.js" async="true" defer data-main="./js/main.js"></script>
其中
-
async='true'
是 script 標(biāo)簽提供的功能,可以異步的下載js文件,不會導(dǎo)致瀏覽器阻塞. -
defer
是因?yàn)?IE 瀏覽器目前不支持async
. -
data-main
是給requirejs
指定入口的js
文件.(就和 webpack 打包工具指定 entry 一樣)
這里的
<script src="./js/require.js" async="true" defer data-main="./js/main.js"></script>
做了兩件事情:
- 導(dǎo)入
require.js
文件. - 讓
main.js
做為整個(gè)前端模塊的入口.
step 3
定義一個(gè) main.js
需要使用到的模塊.
既然這里使用到的是
requirejs
提供的前端化模塊方案.
那么肯定就不能像沒事人那樣寫以前的那種js代碼文件了.
requireJs 提供了一個(gè)全局的 define(name?,[dependencies]?,factory)
用來定義
一個(gè) AMD
的模塊.
其中:
-
name
: 模塊的名字.(一般很少用到這個(gè)參數(shù)) -
dependencies
: 當(dāng)前模塊依賴的模塊.數(shù)據(jù)類型 -
factory
: 一個(gè)工廠函數(shù),用于返回當(dāng)前模塊的API.
代碼格式
define(['moduleA','moduleB','moduleC'],function(moduleA,moduleB,moduleC) {
// 等待 moduleA , moduleB, moduleC 都加載完畢之后,會進(jìn)入到這個(gè)回調(diào)函數(shù).
moduleA.someFn()
moduleB.someFn()
moduleC.someFn()
// 這個(gè)對象就是當(dāng)前定義模塊返回的API.內(nèi)容.
return {
a: moduleA.xxx,
b: moduleB.xxx,
c: moduleC.xxx
}
})
step 4.編造一個(gè)場景,使用rquirejs提供的define()來定義一個(gè)模塊
regex.js
一個(gè)提供正則表達(dá)式驗(yàn)證的AMD
模塊.
define(function () {
const phoneRegex = /^(13|14|15|17|18|19)[0-9]{9}$/, // 手機(jī)號碼(國內(nèi))
emailRegex = /^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$/ // 郵箱
function isPhoneNum (phone) {
return phoneRegex.test(phone)
}
function isEmail (email) {
return emailRegex.test(email)
}
// 此模塊返回兩個(gè)函數(shù)
return {
isPhoneNum,
isEmail
}
})
- 這里的
regex.js
是一個(gè)很簡單的正則驗(yàn)證模塊.沒有依賴其他的模塊功能.所以使用了define(factory)
來定義. - 模塊最終返回了一個(gè)對象,里面包括了兩個(gè)函數(shù)(isPhoneNum,isEmail)
step 5. 使用RequireJS提供的require()來引用regex模塊
讓 main.js
(入口模塊) 使用 regex.js
模塊文件.
既然這里使用到的是
requirejs
提供的前端化模塊方案.
引用模塊需要使用到requirejs
提供的require
接口角寸。
RequireJS 提供了一個(gè)全局的 require([dependencies],factory)
用來引用一個(gè) AMD
模塊(define()定義的)
其中
-
dependencies
: 當(dāng)前require
依賴的js
模塊. 是一個(gè)數(shù)組. -
factory
: 當(dāng)所有模塊都加載完成之后.會觸發(fā)這個(gè)回調(diào)函數(shù).函數(shù)形參是按照模塊的導(dǎo)入順序賦值的.
代碼格式
require(['moduleA','moduleB','moduleC'],function(){
moduleA.someFn()
moduleB.someFn()
moduleC.someFn()
})
在 index.html
導(dǎo)入的
<script src="./js/lib/require.js" async="true" defer data-main="./js/main.js"></script>
main.js
文件中.
require(['./module/regex'], function (regex) {
document.getElementById('phone').onblur = function (e) {
const value = e.target.value
let result = regex.isPhoneNum(value) ? '手機(jī)號碼正確' : '手機(jī)號碼錯(cuò)誤'
console.log(result)
}
document.getElementById('email').onblur = (event) => {
const value = event.target.value
let result = regex.isEmail(value) ? '郵箱賬號正確' : '郵箱賬號錯(cuò)誤'
console.log(result)
}
})
最后測試結(jié)果:
AMD總結(jié):
- 需要在頁面中首先加載 requirejS 文件. 并設(shè)置入口模塊.(
main.js
)
<script src="./js/lib/require.js" async="true" defer data-main="./js/main.js"></script>
- 定義AMD模塊使用 RequireJS 提供的
define(name?,[dependencies]?,factory)
方法定義模塊.
// AMD 在定義模塊時(shí),提倡依賴前置
define(['moduleA','moduleB'],function(moduleA,moduleB){
// some code here with moduleA...moduleB
})
- 導(dǎo)入 AMD 模塊使用 RequreJS 提供的
require([dependencies],factory)
方法導(dǎo)入并使用模塊.
AMD 在使用模塊時(shí),提倡依賴前置
require(['moduleA','moduleB'],function(moduleA,moduleB){
// some code here with moduleA...moduleB
})
CMD & sea.js
CMD 是 Common Module Definition
的縮寫.
它和 AMD
一樣,也是用于前端瀏覽器模塊化開發(fā)的一個(gè)標(biāo)準(zhǔn).(跑在前端瀏覽器中的)
國內(nèi)大神根據(jù)此標(biāo)準(zhǔn)創(chuàng)建了 sea.js
.
為什么有了AMD之后,還要有一個(gè)CMD呢?
AMD & require.js 提倡的是依賴前置.
define(['a','b','c'],function(a,b,c){
})
而 CMD 和 AMD 不同之處在于:
CMD 提倡依賴后置,或者說懶加載依賴.只有在使用到某些框架的時(shí)候,才去加載依賴.
define(function(require,exports,module){
const moduleA = require('a')
if (moduleA.test()) {
// 只有在需要這個(gè)模塊的時(shí)候,才去加載.
const moduleB = require('b')
//.....
}
})
實(shí)現(xiàn)了 CMD 標(biāo)準(zhǔn)的 sea.js
也提供了定義模塊和使用模塊的方法.(模塊怎么定義以及怎么使用的)
- CMD 定義模塊使用
// math.js
define(function(require,exports,module){
function add (a, b) {
return a + b
}
module.exports = {
add
}
})
- CMD 導(dǎo)入模塊使用
// main.js
seajs.use(['./math.js'],function(math){
math.add(1,2)
})
CMD&sea.js 的基本使用步驟.
step 1.需要下載sea.js源代碼
<script src="./sea.3.0.3.js"></script>
和 require.js 不同的是, sea.js 不是指定所謂
data-main
入口js
文件.
sea.js 提供一個(gè)全局的seajs.use([dependencies],callback)
接口,用來使用定義的CMD
模塊.
step 2.
創(chuàng)建一個(gè) regex.js
的正則表達(dá)式驗(yàn)證模塊.
//regex.js
define(function (require, exports, module) {
const phoneRegex = /^(13|14|15|17|18|19)[0-9]{9}$/, // 手機(jī)號碼(國內(nèi))
emailRegex = /^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$/ // 郵箱
function isPhoneNum(phone) {
return phoneRegex.test(18571656584)
}
function isEmail(email) {
return emailRegex.test(email)
}
// 和 commonJS很類似的導(dǎo)出語法.
module.exports = {
isPhoneNum,
isEmail
}
})
注意:
sea.js 提供的是一個(gè)和 commonjs
原理很類似的模塊定義方法.(利用閉包函數(shù)包裹的方式)
step 3.
創(chuàng)建一個(gè)使用此模塊的 main.js
文件
// main.js
seajs.use(['./regex.js'], function (regex) {
window.onload = () => {
document.getElementById('18571656584').onblur = function (e) {
const value = e.target.value
let result = regex.isPhoneNum(value) ? 'CMD-SEAJS-手機(jī)號碼正確' : 'CMD-SEA-JS手機(jī)號碼錯(cuò)誤'
console.log(result)
}
document.getElementById('email').onblur = (event) => {
const value = event.target.value
let result = regex.isEmail(value) ? 'CMD-SEA-JS郵箱賬號正確' : 'CMD-SEA-JS郵箱賬號錯(cuò)誤'
console.log(result)
}
}
})
sea.js 使用全局提供的 seajs.use()
來使用模塊.
step 4.
在界面中導(dǎo)入這個(gè)js文件.
<script src="./main.js"></script>
step 5.
結(jié)果:
CMD模塊使用步驟總結(jié)
- 首先要下載sea.js源代碼,并在頁面中導(dǎo)入此文件虏两。
<script src="./sea.3.0.3.js"></script>
- 使用 seajs 提供的define()函數(shù)定義 CMD 模塊.
define(function(require,exports,module){
//..
if (someCondition) {
// CMD 在導(dǎo)入模塊是提倡依賴后置
const m = require('./someModule.js')
}
module.exports = {}
})
- 利用 seajs 提供的
seajs.use([dependencies],callback)
來使用定義好的模塊.
seajs.use(['a,'b'],function(a,b) {
//....
})
總結(jié):
- 前端模塊化指的是在瀏覽器執(zhí)行環(huán)境中的模塊化.
- 提供前端模塊化的方式有兩種.
-
AMD
異步模塊定義和實(shí)現(xiàn)了此標(biāo)準(zhǔn)的requireJs
-
AMD
提倡依賴前置. - 使用
define()
來定義模塊. - 使用
require()
來使用模塊.
-
-
CMD
通用模塊定義和實(shí)現(xiàn)了此標(biāo)準(zhǔn)的seajs
-
CMD
提倡依賴后置. - 使用
define(function(require,exports,module){})
來定義模塊. - 使用全局提供的
seajs.use([dependencies],callback)
來使用模塊.
-
-