上一節提完了構思和大致實現下面來看具體的html
配置文件主要是是用來讓後端開發自主添加頁面,並經過該配置生成route和加載對應的store,這樣就省去了後端去了解vue-router和vuex的用法了;vue
配置文件格式以下node
這裏採用umd格式開頭是爲了後續nodejs進行調用ajax
(function(global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : (global.__config__ = factory()); })(this, function() { var __config__ = { //規則說明 /** * route : 路由 * path : 模塊路徑 * store : 是否加載對應store * sync : 是否同步加載 */ modules: [ { route: '/', path: 'Login', store: true, sync:true }, { route: '/Main', path: 'Main' }, ... ] } });
有了上面的config文件,咱們就能夠經過配置來來生成router了vue-router
代碼以下vuex
在define前根據config動態define一些模塊用來給業務模塊動態返回template和mixin一些公用方法segmentfault
; (function () { var businessModules = ['vue', 'store/index', 'vue-router'].concat(__config__.map(function (o) { var module = o .route .replace(/\/:[^\\/]*/g, '') .replace(/\//g, '_') if (o.sync) { var func = ";define('business/base/" + module + "',['__module__','business/" + o.path + "/index','text!business/" + o.path + "/tpl.html'],function(factory,businessModule,template){ return factory('" + module + "', businessModule('" + module + "'),template)})" __config__.dynamic(func) return 'business/base/' + module } })) define(businessModules, function (Vue, store, VueRouter) { Vue.use(VueRouter) var m = [] .slice .call(arguments, 3) var routes = __config__.map(function (o, i) { var clone = Object.assign({}, o) clone.name = clone .route .replace(/\/:[^\\/]*/g, '') .replace(/\//g, '_') delete clone.store clone.path = clone.route delete clone.route clone.component = clone.sync ? m[i] : function (resolve) { require(['__module__', 'business/' + o.path + '/index', 'text!business/' + o.path + '/tpl.html'], function (factory, businessModule, template) { resolve(factory(clone.name, businessModule(clone.name), template)) }) } return clone }) var router = new VueRouter({mode: 'hash', routes: routes}) var firstLoad = true var goto = function (to, from, next) { var tName = to.name || '_' var fName = from.name || '_' var toDepth = tName .split('_') .length var fromDepth = fName .split('_') .length toDepth += (tName === '_' ? -1 : 0) fromDepth += (fName === '_' ? -1 : 0) var direction = toDepth - fromDepth if (firstLoad && toDepth > 0) { firstLoad = false next({path: '/'}) } else { store.dispatch('transition', { direction: direction, to: tName, from: fName }) window.setTimeout(function () { next() }) firstLoad = false } } router.beforeEach(function (to, from, next) { var args = arguments if (to.path === '/') { goto.apply(this, args) return } store .dispatch('auth') .then(function () { goto.apply(this, args) }, function () { Vue.$toast({message: '驗證信息已失效,請從新登錄', iconClass: 'fa fa-close'}) window.setTimeout(function () { next({path: '/'}) }) }) }) return {tpl: '<router-view></router-view>', router: router} }) })()
在define前根據config動態define一些模塊用來給store對象添加一些公用getter,mutations和action後端
(function() { var storeModules = [ 'vue', 'vuex', './transition' ].concat(__config__.modules.map(function(o) { var module = o.route.replace(/\//g, '_'); var func = (o.store == true ? ";define('store/modules/base/" + module + "',['__store__factory__','store/modules/" + o.path + "/store'],function(factory,storeModule){ var mb = factory('" + module + "'); var m = new storeModule('" + module + "'); var c = $.extend(true,{},mb, m); return c; });" : ";define('store/modules/base/" + module + "',['__store__factory__'],function(factory){ return factory('" + module + "');});"); __config__.dynamic(func); return 'store/modules/base/' + module; })); define(storeModules, function(Vue, Vuex, transition) { Vue.use(Vuex); var m = [].slice.call(arguments, 3); var modules = {}; __config__.each(function(o, i) { modules[o.route.replace(/\//g, '_')] = m[i]; }); return new Vuex.Store({ state: {}, mutations: {}, actions: { transition: transition }, modules: modules }) }) })();
define([ 'vue', 'vue-router', 'store/index', 'router/index', 'emitter', '__install__' //這裏面主要是對公用控件的一些初始化 Vue.component({...}) ], function(Vue, VueRouter, store, router, Emitter) { window.Vue = Vue; return { run: function() { Vue.config.silent = false; Vue.config.devtools = true; Vue.mixin(Emitter); var $vm = new Vue({ el: 'body > div', store: store, template: router.tpl, router: router.router }); } } })
以Login模塊爲例api
文件路徑/business/Login/index.js
同目錄下還有個tpl.html服務器
define(['vue', 'vuex'], function(Vue, Vuex) { return function module(moduleName) { return { data: function() { return { username: '', password: '' } }, methods: Object.assign( Vuex.mapActions([ 'verify' ]), { sign: function() { var that = this; this.verify({ username: this.username, password: this.password }).then(function() { that.$router.push('/Main'); }, function(mes) { Vue.$toast({ message: mes || '賬號或者密碼錯誤', iconClass: 'fa fa-close' }); }); } }) } } })
對應的store
文件爲/store/module/Login/store.js
define(function() { return function storeModule(module) { this.state = { sign: true, auth: '' //用於存儲登錄成功後的驗證碼,用於後繼登錄狀態驗證 } this.getters = { isLogin: function(state) { return state.sign; } } this.mutations = { success: function(state, param) { state.sign = true; state.auth = param ? param : state.auth; }, fail: function(state) { state.sign = false; state.auth = ''; } } this.actions = { //頁面跳轉過程當中驗證用 verify: function(content, opt) { return new Promise(function(resolve, reject) { $.post('/api/verify', { username: opt.username, password: opt.password }).then(function(data) { if (data.state) { content.commit('success', data.auth); resolve(); } else { content.commit('fail'); reject(); } }, function() { content.commit('fail'); reject("服務器錯誤!請聯繫管理員"); }); }) }, //登錄用 auth: function(content) { return new Promise(function(resolve, reject) { $.get('/api/auth', { auth: content.state.auth }).then(function(data) { if (data) { content.commit('success'); resolve(data); } else { content.commit('fail'); reject(); } }); }); } } } })
平時後端開發時不涉及全局狀態控制時就能夠不用store,ajax能夠直接寫在模塊內
以上就是基於requirejs的vue2項目的核心內容
該項目在不打包的狀況下可以正常運行,各模塊都會在頁面加載時進行預加載;後繼還將進行全部文件打。減小服務器的請求對於store和router這兩個特殊寫發的文件(由於requirejs的r.js打包不識別),要進行特殊處理