模塊化開發(fā)
隨著團(tuán)隊開發(fā)的復(fù)雜化匈庭,我們依賴的代碼庫會越來越多;
安裝
npm install spm -g
spm install seajs
可以安裝:
安裝bower
npm install -g bower
安裝seajs
brwer install seajs
github:
http://github.com/seajs/seajs
也可以下載成一個js文件引入
<script src="../lib/sea.js"></script>
<script>
console.log(seajs.version)
</script>
知識
前端這些模塊管理的實現(xiàn)是基于AMD規(guī)范(異步饼记、管理象迎、加載規(guī)范)荧嵌,在最終實現(xiàn)的時候尊重commndjs規(guī)范(nodejs就是這個),定義模塊時有兩種,第一個是只傳一個參數(shù)就是commndjs規(guī)范啦撮,傳遞多個參數(shù)的時候谭网,寫法尊重moduletransport規(guī)范;
通常define只允許我們定義一個模塊逻族,當(dāng)定義多個模塊的時候蜻底,后面的會覆蓋掉前面的;
seajs文件路徑是以sea.js作為出發(fā)點的 , 如果是'./'則以自身文件夾為出發(fā)點
使用
建立一個de.js文件
seajs.use('de')
在控制面板networks里能看到de.js被加載進(jìn)來了
define
當(dāng)傳遞一個參數(shù)的時候聘鳞,參數(shù)就是一個模塊,參數(shù)可以是任意類型薄辅;
在de.js中:
console.log('hello')
index.html:
seajs.use('de',function(main){
})
控制臺輸出:hello 字符串
define傳遞:
de.js輸入define('hello')
index.html:
seajs.use('de',function(main){
console.log(main)
})
控制臺輸出:hello 字符串
de.js輸入
define({
color:'red',
say:function(){
return 'hello'
}
})
控制臺輸出一個對象
- 如果不寫在define里就是一個undefined
我們還可以傳遞函數(shù),這是一種最復(fù)雜的方式抠璃,工作中基本是這種方法:
這個函數(shù)自帶三個參數(shù):
require:引用其它模塊的工廠方法
exports:返回的接口對象
module:模塊的module屬性集
define(function(require,exports,module){
return {
color:'yellow'
}
})
- 當(dāng)傳遞多個參數(shù)時站楚,兩個或者三個
如果傳遞兩個參數(shù)的時候,第一個參數(shù)表示該模塊依賴的模塊數(shù)組集合搏嗡,最后一個參數(shù)是function窿春;
如果傳遞三個參數(shù)的時候,第一個表示模塊的名稱采盒,第二個表示該模塊依賴的模塊集合旧乞,第三個參數(shù)就是個function;
define('main',[],function(require,exports,module){
return {
color:'yellow'
}
})
模塊的依賴
- 包就是前段說的模塊
- 當(dāng)傳遞模塊名稱的時候磅氨,模塊的名稱就是該名稱尺栖,當(dāng)不傳遞模塊的名稱的時候,該模塊的名稱就是該文件的名稱烦租,通常我們將模塊的名稱與文件的名稱保持一致
我們再新建一個header.js文件:
define(function(){
return {
color:'orange'
}
})
在main.js中引用:
define(function(require,exports,module){
var header = require('./header/header');
console.log(header)
return {
color:'yellow'
}
})
index.html的代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="js/sea.js"></script>
<script>
seajs.use('main',function(main){
console.log(main)
})
</script>
</body>
</html>
控制臺輸出兩個對象延赌;
use
seajs.use(['header/header','header/skin/skin'],function(header,skin){
console.log(header,skin)
})
第一個參數(shù)可以是一個字符串,也可以是一個模塊數(shù)組叉橱,有多少個挫以,在回調(diào)函數(shù)的參數(shù)就有多少個;
我們可以使用header:
define(function(require,exports,module){
var header = require('./header/header');
document.body.style.background = header.color;
return {
color:'yellow'
}
})
- require規(guī)范:
- require不能簡寫窃祝;
- require不能被重新定義掐松;
- 不能賦值 var req = requie;是不可以的
- 不能定義函數(shù) function require 是不可以的
- 不能在子函數(shù)中的參數(shù)中使用require
- 不能在子函數(shù)的作用域內(nèi)重定義(重復(fù)上面三條)
- require的參數(shù)只能是完整的字符串,拼接也不行require('abc' + 'cde')是不可以的粪小;
- require的參數(shù)值如何定義:
參數(shù)值表示的是文件的路徑甩栈,相對于sea.js,當(dāng)然也可以./從自身目錄出發(fā)
項目目錄:
- index.html
- js文件夾
- sea.js
- main.js
- header文件夾
- header.js
- skin文件夾
- skin.js
skin.js:
define(function(){
return 'haha'
})
在main.js中引用:
define(function(require,exports,module){
var header = require('./header/header');
var skin = require('header/skin/skin')
console.log(skin)
document.body.style.background = header.color;
return {
color:'yellow'
}
})
控制臺輸出:haha
require:
- 可以看到是以sea.js為路徑起始點,也就是根目錄糕再;
- 加載js文件量没,后綴名不寫;
define:
require,exports,module不能更改
前面說到定義一個模塊的時候最好名字和文件名一樣突想,默認(rèn)不寫模塊名殴蹄;
如果我們寫了不一樣的名字會怎么樣呢究抓?
header.js中:
define('haha',[],function(){
return {
color:'orange'
}
})
可以看到模塊的名字為haha,依賴為空數(shù)組,文件名是header.js
main.js:
define(['header/header'],function(require,exports,module){
var a = require('haha');
var skin = require('header/skin/skin')
console.log(a,111)
return {
color:'yellow'
}
})
可以看到控制臺可以輸出結(jié)果;
所以
- define的數(shù)組參數(shù)為依賴的模塊路徑
- require為引入的模塊名字
- 如果兩者相同袭灯,就可以直接var header = require('header/header'),不要后綴名.js
exports
- export是保留字刺下,所以使用exports;
- 表示模塊的接口,
第一種:直接對exports添加屬性稽荧,如exports.color = 'red';
第二種:通過module來定義橘茉,module.exports.color = 'yellow';
第三種:通過module來定義,module.exports = {color: 'orange'};
第四種:通過return來定義姨丈,return {color:'green'};
我們在一個模塊中定義接口的時候畅卓,只能使用一種,不能混用蟋恬,后面的會覆蓋前面的翁潘;
我們不可以直接對exports賦值新對象
main.js
define(function(require,exports,module){
var a = require('header/header')
console.log(a)
})
header.js
define(function(require,exports,module){
exports.color = 'red'
})
注意:使用exports接口的header模塊,require,exports,module三個參數(shù)必須寫上;
第二種方式header.js:
define(function(require,exports,module){
module.exports.color = 'red'
})
第三種方式header.js:
define(function(require,exports,module){
module.exports={
color:'blue'
}
})
第四種方式header.js:
define(function(require,exports,module){
return {
color:'white'
}
})
module
我們console.log(module)歼争;
有四個屬性:
- id 模塊名 默認(rèn)為路徑一致 如果id不與uri一樣則要分開引用
- uri 路徑
- dependencies 依賴的模塊 放在數(shù)組里
deps 依賴的模塊 放在對象里 - exports是我們返回的接口拜马;
小案例
- 項目根目錄
- index.html
- js文件夾
- main.js
- sea.js
- lib文件夾
- dom.js
- event.js
- string.js
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button id="btn">猜一猜</button>
<div id="out"></div>
<script src="js/sea.js"></script>
<script>
seajs.use('main',function(){})
</script>
</body>
</html>
main.js:
define(function(require,exports,module){
var Evt = require('lib/event');
var Dom = require('lib/dom');
var Str = require('lib/string')
var msg = 'i don\'t know'
Evt.on('btn','click',function(){
Dom.html('out',Str.upper(msg))
})
})
dom.js
define(function(){
var Dom = {
g: function(id){
return document.getElementById(id);
},
html:function(id,html){
if(html){
this.g(id).innerHTML = html;
}else{
return this.g(id).innerHTML;
}
}
}
return Dom;
})
event.js
define(function(require,exports,module){
var Dom = require('lib/dom')
var Evt={
on: function(id,type,fn){
Dom.g(id)["on"+type] = fn;
}
}
return Evt;
})
string.js
define(function(){
var Str = {
upper:function(str){
return str.toUpperCase();
}
}
return Str;
})
require.async異步調(diào)用,跟use方法很像沐绒,我們在頁面初始化使用use異步加載模塊俩莽,在模塊內(nèi)部想實現(xiàn)模塊的異步加載,就要用require.async方法乔遮;
案例一:
header.js:
define(function(require,exports,module){
return {
color:'white'
}
})
main.js:
define(function(require,exports,module){
var header = require('header/header')
return {
color: header.color
}
})
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
html,body{
height:100%;
}
</style>
</head>
<body>
<script src="js/sea.js"></script>
<script>
seajs.use('main',function(main){
console.log(main)
})
</script>
</body>
</html>
就可以得到header的color為white;
如果采用require.async(第一個參數(shù)為字符串也可以是數(shù)組豹绪,第二個參數(shù)是回調(diào)函數(shù)),和use很像申眼;
define(function(require,exports,module){
// var header = require('header/header')
var header = require.async('header/header',function(header){
console.log(111,header)
})
return {
color:header.color
}
})
- 再來看下面的代碼:
var loadSkin = false;
if(loadSkin){
var skin = require('header/skin/shin')
}else{
var header = require('header/header')
}
其實兩個文件都會加載請求回來,但是skin打印是undefined
如果換成異步加載:
var loadSkin = false;
if(loadSkin){
var skin = require.async('header/skin/shin')
}else{
var header = require.async('header/header')
}
可以看到不會執(zhí)行的代碼文件不會加載蝉衣;
seajs.config({})
寫在index.html seajs.use上面
seajs.config接收一個對象參數(shù)括尸,用來配置一些選項參數(shù)的,接收一個對象病毡,里面的屬性值濒翻,就是我們配置的選項;
1. alias
alias:{
util:'lib/unitl-2.0'
}
這個可以解決一個問題:lib里面版本庫文件啦膜,如果在main.js,header.js等等一大堆文件中引用:
var util = require('lib/util-2.0');
如果一天這個文件升級到了2.1有送,那么就要去打開這些引用了它的文件去修改,就會造成麻煩僧家,所以alias就是解決這個問題的雀摘;
在alias中把這個文件定義為util,在mainjs,headerjs等文件中要使用它八拱,只需要
define(function(require,exports,module){
var util = require('util');
console.log(util)
})
這樣如果文件版本升級阵赠,只需要更改alias里面的路徑即可涯塔;
2. paths
paths:{
m:'module/header'
}
如果我們要引用module/header下面的header.js
var header = require('module/header/header');
如果按照上面定義好了的路徑,以后引用這個文件夾下的文件只需要:
var header = require('m/header')
3. vars
vars:{
hd:'header'
}
如何使用:
// var a = require('module/header/skin/skin')
var a = require('module/{hd}/skin/skin')
如果:
vars:{
hd:'header/skin'
}
則
var a = require('module/{hd}/skin')
通過{}來匹配
4. map
map:[
['.js','.min.js']
]
映射清蚀,把所有的js文件做匹配處理匕荸;
如果有文件打包后,文件名可能不同枷邪,可以通過這個來處理榛搔;