終於到講授如何整合avalon社區這個最強大的組件,基於狀態機的路由系統了!javascript
基於狀態機的路由系統,據我所知,目前世界上只有三款,angular社區的ui-router, 網易出品的stateman, avalon社區的mmState!css
mmState最初是我寫的,基於mmRouter上擴展出來,到0.4版時只有400行,後來通過我同事參考ui-router,迅速爆漲到1000行,知足各方面的需求(這其中,社區上也有很多人貢獻代碼)。所以如今讓我重拾mmState的源碼,我也幾乎看不懂。。。。html
以前mmRouter 有一個小BUG,切換視圖時會執行兩次回調,這個我修了不當心又引起mmState不可用,所以本例請使用最新的0.9版。java
mmState 0.9的下載地址jquery
avalon則仍是建議使用1.4.*或1.5.*的最新版本。webpack
咱們沿着上一篇項目的目錄,此次要將mmState, mmPromise都要拷貝過來!git
如今目錄變成這個樣子:github
咱們看一下這個頁面吧(state.html)web
<!DOCTYPE html> <html> <head> <title>mmState組件</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="dist/common.js"></script> <script src="dist/state.js"></script> </head> <body ms-controller="test"> <ul> <li><a href="#!/aaa">aaa</a></li> <li><a href="#!/bbb">bbb</a></li> <li><a href="#!/aaa/555">aaa.son</a></li> <li><a href="#!/bbb/111">bbb.son</a></li> </ul> <div ms-view></div> </body> </html>
這個東西只要改改就是一個經典的後臺系統,不過我目前不想把示例搞得這麼複雜。之後會呈上更好的東西。框架
咱們看一下其主JS文件,裏面用avalon.state定義了4個狀態對象
var avalon = require("avalon") require("./mmRouter/mmState") var vm = avalon.define({ $id: "test", args: "" }); avalon.state("aaa", { url: "/aaa", views: { "": { template: "1111" } } }).state("bbb", { url: "/bbb", views: { "": { template: "2222" } } }).state("aaa.son", { url: "/:bbb", views: { "": { template: "這是子級{{args}}" } }, onEnter: function (a) { vm.args = a } }).state("bbb.son", { url: "/:bbb", views: { "": { templateProvider: function () { return new Promise(function (rs) { require.ensure([], function (tt) { rs(require("text!./statetemp.html")) }) }) } } }, onEnter: function (a) { vm.args = a } }) avalon.history.start(); avalon.router.navigate("aaa") //默認打開aaa狀態 avalon.scan(0, vm)
每個狀態對象都有它本身的名字,對應的URL匹配規則,還有views對象。views對象有一個template或templateProvider屬性,其實在實際項目中,我償都應該使用templateProvider,返回一個Promise對象,在Promise裏面用上節提到的require.ensure異步加載視圖。
若是想了解更詳細的用法,可見這裏
state.js還依賴一個頁面模板,statetemp.html
<b>這是經過異步加載的{{args}}</b>
最後咱們在webpack.config.js里加一行代碼,指明入口文件
var webpack = require("webpack"); var path = require("path"); var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js'); module.exports = { entry: { index: './dev/index', //咱們開發時的入口文件 router: './dev/router', router2: './dev/router2', ensure: './dev/ensure', state: './dev/state' }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", publicPath:"dist/", //給require.ensure用 chunkFilename: "[name].chunk.js"//給require.ensure用 }, //頁面引用的文件 module: { loaders: [ {test: /\.css$/, loader: 'style-loader!css-loader'} ], preLoaders: [ {test: /\.js$/, loader: "amdcss-loader"} ] }, plugins: [commonsPlugin], resolve: { extensions: ['.js', "", ".css"], alias: { jquery: path.join(__dirname, 'dev/jquery/jquery.js'), avalon: path.join(__dirname, 'dev/avalon/avalon.shim'), //在正常狀況下咱們以CommonJS風格引用avalon,以require('avalon') '../avalon': path.join(__dirname, 'dev/avalon/avalon.js')//因爲oniui都以是../avalon來引用avalon的,須要在這裏進行別名 } } }
而後執行webpack就能看到效果
你們仔細一看的話,其實這代碼早是出奇的少,比angular的少量多,許多操做都是咱們框架默認幫你處理好,因此我本人認爲其友好度與易用性遠勝於ui-router。用好mmState+webpack能迅速爲你們搭建一個SPA應用,不管是後臺仍是手機端,你能享受到MVVM的好處。