http://www.cnblogs.com/zt-blog/p/7779384.html
寫在前面:
因為最近總結自己之前做過的東西,所以順便總結了這一篇,要發布文章時,剛好看到手機推送消息“angular5發布啦”啊哈哈哈哈哈哈。我不管我還是要把關於angular1的這篇文章放上來因為還涉及到webpack呢啊哈哈哈哈哈哈哈哈……
Angularjs+webpack實現模擬微信菜單編輯功能
1 環境配置:Angularjs
1.1 安裝nodejs (npm): 略
1.2 安裝webpack (本地)
npm install --save-dev webpack
npm install --save-dev webpack@<version>
1.3 創建webpack配置文件
webpack.config.js
1.4 安裝angularjs
npm install angular@1.5.8 –save-dev
1.5 運行
webpack
webpack-dev-server (webpack-dev-server --hot --inline)
http://localhost:8080/
1.6 關於熱加載:
本地開發時,設置熱加載能夠實現本地更改即時反應到頁面效果。
設置時注意:
配置publicPath;
bundle.js在server中的路徑: http://localhost:8080/{publicPath}/bundle.js
1.7 安裝loader
Webpack本身只識別js文件,但是項目中通常除了js文件外,還有css,img,url等各種文件,loader就是為了讓webpack也能識別這些文件並將其模塊化。
安裝:
npm install style-loader css-loader --save-dev
npm install file-loader --save-dev
(所有loader詳見package.json)
1.8 實現模塊化
Webpack是以模塊方式(入口文件+模塊依賴)管理項目的,所以我們需要給項目加入模塊化功能,我們采用ES6的模塊化實現方式,需要先安裝babel加載器編譯ES6:
npm install --save-dev babel-loader babel-core babel-preset-es2015
2 Angularjs
2.1 模塊
ng,ngRoute,ngSanitize,ngAnimate…
定義angular模塊:
angular.module('app.wxPageModule', []);
angular.module('app. wxPanelModule', []);
2.2 指令 v.s. 組件
Angular內置指令: ngApp, ngController, ngModel, ngView, … , {{}}
自定義指令--組件:
wxPanelModule.directive('wxPanel', function() {
return {
restrict: 'E', //AEC
templateUrl: './src/components/wxPanel/wxPanelTemplate.html',
link: function($scope, elm, attr, controller) {
//可以操作dom,例如綁定dom事件
},
controller: function($scope, $element, $attrs) {
//組件的控制器
},
scope: {
//隔離作用域,定義組件變量
}
}
})
自定義指令依賴angularjs的HTML編譯器($compile)對元素附加一些特定的行為。
2.3 控制器 v.s. scope
定義控制器:
wxPanelModule.controller('wxPanelCtrl', [ '$scope', function($scope){ // $scope作用域
//數據模型
$scope.a=1;
$scope.getA=function(){ … };
//添加方法,可以在模板中通過表達式或ngClick等事件調用
}])
作用域scope:
當一個控制器通過 ng-controller 指令被添加到DOM中時,ng 會調用該控制器的構造函數來生成一個控制器對象,這樣,就創建了一個新的子級 作用域(scope)。在這個構造函數中,作用域會作為$scope參數注入其中,並允許用戶代碼訪問它。
一般情況下,我們使用控制器做兩件事:
1.初始化 $scope 對象
2.為 $scope 對象添加行為(方法)
控制器定義在各個模塊中,每個控制器都有自己的作用域,因此形成一條作用域鏈,層級結構對應dom樹結構。根作用域為$rootScope。
作用域提供了$watch方法監聽數據模型變化,提供了$apply(執行$digest,檢查所有由 $watch監聽的數據並將其之前的值進行比較)方法將飛angular環境中發生的數據模型改變同步到angular作用域中。 (applyàdigestàwatch)
|
作用域的事件傳播機制:
$broadcast $emit $on
Service:
控制器應該盡可能保持單純,例如獲取后台服務數據的邏輯應該封裝在service中,通過依賴注入到controller中。Service同樣也是定義在module上面的。
2.4 雙向數據綁定
據模型始終是應用的單一數據源
臟檢查----見scope小節
2.5 依賴注入DI
背后是通過Injector來創建和查找依賴的。
注入方式:
moduleA.controller('ctrl1',['$scope','dep1', 'dep2',…, function($scope, dep1, dep2,…){ … }]);
2.6 路由 (原生 v.s. ui-router)
3 webpack
webpack幫助我們綁定各個模塊,並構建出一張依賴圖。
3.1 配置
配置文件導出的是一個對象(CommonJS模塊)
示例:
const path = require('path');
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: "/assets/",
filename: 'bundle.js' //"bundle-[name]-[hash:8].js",
},
module: {
rules: [{
test: /\.js$/,
use: 'babel-loader?presets=es2015'
}, {
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
3.2 加載器
將各種類型的文件進行模塊化,之后我們就可以import了。例如有了css-loader我們就可以直接在js文件里import css文件。
特點:鏈式;可接收參數;最終返回javascript ;
更多loader請參考:https://webpack.js.org/loaders/
3.3 插件
插件是對loader的補充,可以用來做優化/壓縮等,webpack本身也是也是一種插件的形式。
e.g.代碼壓縮:
- 引入插件: const webpack = require('webpack');
- new出一個新實例:new webpack.optimize.UglifyJsPlugin()
注:使用js壓縮時,最好使用數組方式依賴注入,否則可能壓縮不成功。
更多插件請參考: https://webpack.js.org/plugins/
3.4 運行
webpack
webpack-dev-server (webpack-dev-server --hot --inline)
http://localhost:8080/
官網:https://webpack.js.org/concepts/
4 注意
4.1 Angular模塊 v.s. ES6模塊化
Angular模塊:
- ng,ngRoute,ngSanitize,ngAnimate… ; 依賴注入;
2. 自定義的angular模塊,如angular.module('app.wxPageModule', []);
ES6模塊:
import …
export …
以文件為單位
4.2 $watch效率
Angular進行為實現雙向綁定,進行臟檢查時會頻繁用到$watch方法,所以不要在此方法里做與dom相關的操作,影響效率。
一個angular頁面理想狀況為200左右的$watch,一般大家默認2000$watch為上限(IE),這是為了頁面更好的體驗效果,而並不意味着一定是angular dirty check上限。
4.3 html5Mode
$locationProvider.html5Mode(true).hashPrefix('!');
4.4 Webpack多個loader倒序執行
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
順序:postcss-->css-->style
最后的最后,demo的github地址: https://github.com/tinatingzhang/angualrjs_webpack
angular.element(aDomElement).XXX
//AMD
require(['moduleA', 'moduleB'], function (moduleA, moduleB){
alert('加載成功');
});
//CMD
seajs.use("../static/hello/src/main")
//CommonJS
module.export = {
name:'rouwan'
}
//es6模塊
import {module1, module2} form './module.js';
export {module1}