一、關于模塊化編程
1.1傳統代碼的缺陷
隨著網站功能逐漸豐富,網頁中的js也變得越來越復雜和臃腫。
原有通過script標簽來導入一個個的js文件這種方式已經不能滿足現在互聯網開發模式,并且這樣寫有很大的 缺點,
首先,加載的時候,瀏覽器會停止網頁的渲染,加載的文件越多,那么網頁失去響應的時間越長,
其次,由于js文件之間存在依賴關系,因此必須嚴格保證加載順序,依賴性大的模塊一定要放在最后加載,當依賴關系很復雜的時候,代碼的編寫和維護都會非常困難。
所以我們需要團隊協作、模塊復用、單元測試等等一系列復雜的需求。
二、什么是模塊化及模塊化編程規范
模塊化是只在處理某些問題的時候,按照一種分類思想對功能進行模塊化的管理和使用。
2.1 require.js的誕生
require.js的誕生就是為了解決上述<script>加載問題。
AMD
require.js加載的模塊,采用AMD規范。也就是說,模塊必須按照AMD的規定來寫。即需要用define()來定義模塊和require(),后續會介紹如何定義模塊
對于模塊化的發展暫不做詳細介紹,百度很6的~
2.2require.js的的加載
先去官網下載最新版本,下載后,可以選擇把它放在文件的根目錄下或者是js文件下
<script type="text/javascript" src="js/require.js" ></script>
為了避免加載文件的時候造成網頁失去響應。解決辦法有倆個,一個是把文件的加載放在網頁的最底部,一個是寫成下面這樣
<script src="js/require.js" async="async" ></script>
async屬性表明這個文件需要異步加載,避免網頁加載的時候失去響應。
加載require.js之后,需要加載我們自己的js文件代碼,假設我們自己的代碼文件是app.js,也放在根目錄下,那么就寫成下面這樣
<script type="text/javascript" src="js/require.js" data-main="app"></script>
data-main這個屬性的作用是指定我們網頁程序的主模塊。這個文件會第一個被require.js加載。由于require.js默認的文件后綴名是js,所以可以把app.js簡寫成app。
2.3 主模塊的寫法
一旦我們定義了主模塊的js文件,意思這個就是整個網頁的入口代碼,所有的代碼都從這開始運行。
如果主模塊代碼不依賴于其他任何模塊,那么可以直接寫JavaScript代碼。
這樣就失去了require.js的意義了,因為正常情況下,主模塊都會依賴于其他模塊,這時就需要遵守AMD規范。
看栗子,格式像這樣
// app.js
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
.......
});
require()函數
require()函數接受兩個參數。
第一個參數是一個數組,表示程序所依賴的模塊,即主模塊依賴['moduleA', 'moduleB', 'moduleC']這三個模塊;
第二個參數是一個回調函數,當前面指定的模塊都加載成功后,它將被調用。加載的模塊要以參數形式傳入回調函數,從而在回調函數內部就可以使用這些模塊。
舉個栗子
require(["a","b","c"],function(A,B,C){
.....something.....
})
此時各個模塊之間的關系是這樣的,index.html和app.js和modules文件架 在根目錄下,modules文件下有moduleA,moduleB,moduleC三個文件夾,里邊分別有a.js 和 b.js 和 c.js。
require.js會先加載'a', 'b', 'c',然后再運行回調函數。主模塊的代碼就寫在回調函數中。
2.4模塊的加載
上一節的栗子中,主模塊的依賴模塊是'a', 'b', 'c'
文件名分別為a.js ,b.js ,c.js 然后自動加載
使用require.config()方法,我們可以對模塊的加載行為進行自定義。require.config()就寫在主模塊(app.js)的頭部。參數就是一個對象,這個對象的paths屬性指定各個模塊的加載路徑。
栗子
//通過require.config方法來配置要導入的模塊路徑
require.config({
paths:{
//這里寫要導入的路徑和對應生成的模塊名字
a:"modules/moduleA/a",
b:"modules/moduleB/b",
c:"modules/moduleC/c"
}
})
另注
1.如果模塊在另一臺主機上,也可以直接指定它的網址。
2.如果在這文件在同在其他弄一個文件夾內,比如都在lib文件架內,也可以指定baseUrl
2.5 AMD定義模塊
AMD模塊必須采用define()函數來定義
1.如果一個模塊不依賴于其他模塊,那么可以直接定義在define()函數中。
假設上栗中的a.js模塊不依賴于其他模塊,那么a.js中的代碼如下
//define定義模塊(不依賴于任何其他模塊)
define(function () {
//加法運算
function add (x, y) {
return x + y;
}
return {
add : add
}
})
2.定義模塊的時候如果有依賴于其他模塊的話,我們就可以把第一個參數加入,第一個參數是一個數組,數組中就是依賴模塊的名字或者路徑。
如果這里寫路徑,注意是相對于app.js而言的路徑
假設上栗中的b.js是依賴于jquery和a.js模塊的,那么我們可以在第一個參數中引入,代碼如下
//定義模塊的時候如果有依賴于其他模塊的話,我們就可以把第一個參數加入
//第一個參數是一個數組,數組中就是依賴模塊的名字或者路徑
//如果這里寫路徑需要注意是相對于app.js而言的路徑
define(['jquery', './modules/moduleA/a'], function ($, A) {
//改變div顏色
function changeColor () {
$("#box").css({
//將div的北京變成藍色
backgroundColor : "red"
});
}
//私有方法(說白了就是給自己用,不支持導出這個功能)
//計算兩數之差
function mul (x, y) {
return x - y;
}
function addAndMul (x, y) {
//調用自身的兩個函數
changeColor();
//用到了A模塊里的功能和自身模塊的私有方法
return A.add(x, y) + mul(x, y);
}
//因為后續數據需要反饋,所以一定要return
return {
addAndMul : addAndMul
}
});
當require()函數加載上面這個模塊的時候,就會先加載他所依賴的模塊。
3.為了方便理解下面內容,我們在c.js中也定義一個模塊,其代碼如下
define(['a', 'b'], function (A, B) {
function changeColor () {
$("#box").css({
//將div的背景變成藍色
backgroundColor : 'blue'
});
}
function fn (x, y) {
changeColor();
return A.add(x, y) + B.addAndMul(x, y);
}
//因為后續數據需要反饋,所以一定要return
return {
fn : fn
}
});
2.6 模塊的調用
此時我們定義了了三個模塊。分別為a.js 和b.js 和 c.js,并在主模塊app.js中引入了三個模塊。
此時我們需要調用這三個模塊,并發揮他們的功能,因此,在app.js中,我么除了引入三個模塊的路徑,還需要調用,代碼如下
//通過require方法來導入模塊
//如果上面配置了路徑,數組里導入的時候直接就可以寫上面路徑對應的模塊名字即可
//jquery比較特殊,叫jquery以外其他名字的話,導出模塊會是undefined
//注意:模塊支持導出的話,一定要對應上,不支持導出的模塊,我們放在數組中的最后
require(['jquery', 'a', 'b', './modules/moduleC/c'], function (j, A, B, C) {
console.log($);
console.log(j);
//使用A模塊的功能
console.log(A.add(1, 2));
//使用B模塊的功能
console.log(B.addAndMul(1, 2));
//使用C模塊的功能
console.log(C.fn(1, 2));
});
調用了app.js需要依賴的a,b,c三個模塊,又進行了引用,那么此時app.js中的全部代碼如下
//通過require.config方法來配置要導入的模塊路徑
require.config({
paths : {
//這里寫要導入的路徑和對應生成的模塊名字
jquery : './lib/jquery',
a : './modules/moduleA/a',
b : './modules/moduleB/b'
}
})
//通過require方法來導入模塊
//如果上面配置了路徑,數組里導入的時候直接就可以寫上面路徑對應的模塊名字即可
//注意:模塊支持導出的話,一定要對應上,不支持導出的模塊,我們放在數組中的最后
require(['jquery', 'a', 'b', 'modules/moduleC/c'], function (j, A, B, C) {
//使用A模塊的功能
console.log(A.add(1, 2));
//使用B模塊的功能
console.log(B.addAndMul(1, 2));
//使用C模塊的功能
console.log(C.fn(1, 2));
});
注意代碼中c模塊的變化了么?你再仔細瞅瞅?說好的引用呢?
溫馨提示,也要注意b和c里面的代碼哦
如果在配置依賴的模塊路徑沒有配置,那么在require調用的時候,在數組參數中寫其路徑也是可以的。
主頁面index.html中沒有實際的內容,只是引用,代碼如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box{
width: 200px;
height: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div id="box"></div>
<!-- 導入requireJS庫 -->
<!-- data-main可以導入主入口文件app是指app.js -->
<script type="text/javascript" src="lib/require.js" data-main="app"></script>
</body>
</html>
此時運行index.html ** 注意 div的顏色。。**
你覺得對么?按照加載的順序,應該最后加載c.js div的顏色怎么是紅色的?應該是藍色的才對?
因為我們在c.js中return的時候,又調用了b.js,所以最后又加載了b.js,所以,div變成了紅色~那么,如何解決這個問題呢?用變量存起來不就好啦 -,c.js中的代碼如下
define(['a', 'b'], function (A, B) {
function changeColor () {
$("#box").css({
backgroundColor : 'blue'
});
}
function fn (x, y) {
var num = A.add(x, y) + B.addAndMul(x, y);
changeColor();
return num;
}
return {
fn : fn
}
});
此時我們再輸出一下結果
此篇文章助大家理解require.js,真正的require.js用法,可沒這么簡單呢。
不要吝嗇贊美,喜歡就點贊啦