上一节提完了构思和大体实现下面来看具体的
配置文件config
配置文件主要是是用来让后端开发自主添加页面,并通过该配置生成route和加载对应的store,这样就省去了后端去了解vue-router和vuex的用法了;
配置文件格式如下
这里采用umd格式开头是为了后续nodejs进行调用
(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' },
...
]
}
});
路由router
有了上面的config文件,我们就可以通过配置来来生成router了
代码如下
在define前根据config动态define一些模块用来给业务模块动态返回template和mixin一些公用方法
;
(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: router}
})
})()
状态管理store
在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
})
})
})();
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(Emitter);
var $vm = new Vue({
el: 'body > div',
store: store,
template: router.tpl,
router: router.router
});
}
}
})
模块业务的写法
以Login模块为例
文件路径/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打包不识别),要进行特殊处理