思路和大致实现在上一节中有提到。我们看一下具体的配置文件。config配置文件主要是用来让后端开发者可以独立添加页面,并通过这个配置来生成路由和加载对应的store,这样就省去了后期了解vue-router和vuex的用法的时间;配置文件的格式如下,umd格式开头,用于后续的nodejs调用exports=factory():(global.__config__=factory());})(this,function(){var__config__={//规则描述/***route:route*path:模块路径*store:是否加载对应的store*sync:是否同步加载*/modules:[{route:'/',path:'Login',store:true,sync:true},{route:'/Main',path:'Main'},...]}});Routingrouter有了上面的config文件,我们就可以通过配置生成router了。代码如下在定义之前,根据config动态定义一些模块动态返回给业务模块template和mixin的一些public方法;(function(){varbusinessModules=['vue','store/index','vue-router'].concat(__config__.map(function(o){varmodule=o.route.replace(/\/:[^\\/]*/g,'').replace(/\//G,'_')if(o.sync){varfunc=";define('business/base/"+module+"',['__module__','business/"+o.path+"/index','text!business/"+o.path+"/tpl.html'],function(factory,businessModule,template){returnfactory('"+module+"',businessModule('"+module+"'),template)})"__config__.dynamic(func)return'business/base/'+module}}))define(businessModules,function(Vue,store,VueRouter){Vue.use(VueRouter)varm=[].slice.call(arguments,3)varroutes=__config__.map(function(o,i){varclone=Object.assign({},o)clone.name=clone.route.replace(/\/:[^\\/]*/g,'').replace(/\//g,'_')deleteclone.storeclone.path=clone.routedeleteclone.routeclone.component=clone.sync?m[i]:函数(解析){require(['__module__','business/'+o.path+'/index','text!business/'+o.path+'/tpl.html'],function(factory,businessModule,template){resolve(factory(clone.name,businessModule(clone.name),template))})}returnclone})varrouter=newVueRouter({mode:'hash',routes:routes})varfirstLoad=truevargoto=function(to,from,next){vartName=to.name||'_'varfName=from.name||'_'vartoDepth=tName.split('_').lengthvarfromDepth=fName.split('_').lengthtoDepth+=(tName==='_'?-1:0)fromDepth+=(fName==='_'?-1:0)vardirection=toDepth-fromDepthif(firstLoad&&toDepth>0){firstLoad=falsenext({path:'/'})}else{store.dispatch('transition',{direction:direction,to:tName,from:fName})window.setTimeout(function(){next()})firstLoad=false}}router.beforeEach(function(to,from,next){varargs=argumentsif(to.path==='/'){goto.apply(this,args)return}store.dispatch('auth').then(function(){goto.apply(this,args)},function(){Vue.$toast({message:'验证信息无效,请重新登录',iconClass:'fafa-close'})window.setTimeout(function(){next({path:'/'})})})})return{tpl:'',router:router}})})()statemanagementstore根据配置动态定义一些模块,在定义之前添加一些publicgetters,mutationsandaction(function(){varstoreModules=['vue','vuex','./transition'].concat(__config__.modules.map(function(o){varmodule=o.route.replace(/\//g,'_');varfunc=(o.store==true?";define('store/modules/base/"+module+"',['__store__factory__','store/modules/"+o.path+"/store'],function(factory,storeM模块){varmb=factory('"+module+"');varm=newstoreModule('"+module+"');varc=$.extend(true,{},mb,m);返回c;});":";define('store/modules/base/"+module+"',['__store__factory__'],function(factory){returnfactory('"+module+"');});");__config__.dynamic(func);return'store/modules/base/'+module;}));define(storeModules,function(Vue,Vuex,transition){Vue.use(Vuex);varm=[].slice.call(arguments,3);varmodules={};__config__.each(function(o,i){modules[o.route.replace(/\//g,'_')]=m[i];});returnnewVuex.Store({state:{},mutations:{},actions:{transition:transition},modules:modules})})})();vue主程序定义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(发射器);var$vm=newVue({el:'body>div',store:store,template:router.tpl,router:router.router});}}})模块业务写法以登录模块为例。还有一个tpl.htmldefine(['vue','vuex'],function(Vue,Vuex){returnfunctionmodule(moduleName)和/business/Login/index.js在同一个目录下{return{data:function(){return{username:'',password:''}},methods:Object.assign(Vuex.mapActions(['verify']),{sign:function(){varthat=this;this.verify({username:this.username,password:this.password}).then(function(){that.$router.push('/Main');},function(mes){Vue.$toast({message:mes||'账号或密码错误',iconClass:'fafa-close'});});}})}}})对应的store文件为/store/module/Login/store.jsdefine(function(){returnfunctionstoreModule(module){this.state={sign:true,auth:''//used登录成功后保存验证码,用于后续登录状态验证}this.getters={isLogin:function(state){returnstate.sign;}}this.mutations={success:function(state,param){state.sign=true;state.auth=param?param:state.auth;},失败:函数(状态){state.sign=false;state.auth='';}}this.actions={//页面跳转时验证:function(content,opt){returnnewPromise(function(resolve,reject){$.post('/api/verify',{username:opt.username,密码:opt.password}).then(function(data){if(data.state){content.commit('success',data.auth);resolve();}else{content.commit('fail');reject();}},function(){content.commit('fail');reject("服务器错误!请联系管理员");});})},//loginwithauth:function(content){returnnewPromise(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打包不识别),需要特殊处理