終於到講授如何整合avalon社區這個最強大的組件,基於狀態機的路由系統了!
基於狀態機的路由系統,據我所知,目前世界上只有三款,angular社區的ui-router, 網易出品的stateman, avalon社區的mmState!
mmState最初是我寫的,基於mmRouter上擴展出來,到0.4版時只有400行,后來經過我同事參考ui-router,迅速爆漲到1000行,滿足各方面的需求(這其中,社區上也有不少人貢獻代碼)。因此現在讓我重拾mmState的源碼,我也幾乎看不懂。。。。
之前mmRouter 有一個小BUG,切換視圖時會執行兩次回調,這個我修了不小心又引發mmState不可用,因此本例請使用最新的0.9版。
avalon則還是建議使用1.4.*或1.5.*的最新版本。
我們沿着上一篇項目的目錄,這次要將mmState, mmPromise都要拷貝過來!
現在目錄變成這個樣子:
我們看一下這個頁面吧(state.html)
<!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的好處。
