在五一节之前和一网友讨论前端技术时,对方提到vue、vue-route如果配合requirejs应用。当时的我没有想得很明白,也没能这位网友一个准确的回复,但我许诺于他五一研究后给他一个回复。本是一天的研究却被我搞成了研究了一周,这拖延症。。。
闲话少数,进入正题
代码结构说明:
此示例没有样式,只是为了验证require如何加载一个vue组件,以子路由的动态注入的能力,示例代码下载。
一个.vue文件可以包含模板、Js类、样式(可以不要)等三块。但我们通过vue的官网可以知道,vue提供了compile对象方法,可以把模板编译成VNode。并且我们通过webpack打包后生成的文件可以看出模板与Js类是混淆在一起了。这也就说明vue的组件就是一个Js对象。如下图所示:
引入这三个都很容易,并将这三个注入到Vue对象也是相对简单的,难道的是需要解决动态注入向vue-route实例注入路由,以及vuex的动态加入一个数据模块的能力。好在这两点官网都给出了解决方案:
apt.init = function(){
this.store = Object.create({
modules:{}
});
this.Vue.use(VueRouter);
this.Vue.use(Vuex);
this.router = new VueRouter();
this.store = new this.Vuex.Store(this.store);
}
首先提供一个init方法,对Vue对象进行一些初始化,也就是把Vuex、vue-route都注入到Vue对象中。在这里我把创建的vuex和vue-route的实例都放到this对象,方便后面提供给组件注册实使用。 创建Vue实例:
apt.createVue = function(){
this.vue = new this.Vue({
store: this.store,
router: this.router,
computed: {
childs: function(){
if(!this.$store.state.router) return null;
return this.$store.state.router.childs;
}
}
});
return this.vue;
}
只创建vue对象,没有进行mount。 为其他模块提供的上下文:
apt.createContext = function(){
return {
Vue: this.Vue,
router: this.router,
$vue: this.vue
};
}
从项目结构图中可以看出在modules文件夹中定义了两个组件,分别是:routet和title,而他们的模板则是一个html文件。以下是这类组件如何加载的代码:
apt.acquire = function(path){
var arrayPath;
if(!this.isArray(path)){
arrayPath = [path];
}else{
arrayPath = path;
}
var promise = this.dfd(function(dfd){
require(arrayPath,function(){
dfd.resolve(Array.prototype.slice.call(arguments));
},function(error){
dfd.reject(error);
});
}).promise();
return promise;
}
apt.createComponent = function(componentName){
//可以重载,读取.vue的文件
var path = this.$modulePrefix + componentName,
html = 'text!' + path + '/index.html',
js = path + '/index.js',
self = this;
var promise = this.acquire([html,js]);
promise.done(function(result){
var obj = result[1], content = result[0];
obj.template = content;
obj.__path__ = path;
self.$components.push(obj);
});
return promise;
}
说明: acquire:提供通过require加载JS或者是html等文件的方法,并返回一个promise,这样就方便调用者使用。 createComponet:会根据调用传入的名称在modules文件夹中找出对应的js和html文件,然后调用acquire加载组件。
提供注册全局组件方法
apt.registerGlobalComponents = function(componentNames){
var gloadComponet = componentNames, self = this;
var promises = gloadComponet.map(function(data,index){
return self.createComponent(data);
});
var dfd = this.dfd();
$.when.apply(null, promises).done(function(){
var _router = [];
self.$components.forEach(function(data,index){
self.Vue.component(data.name, data);
_router.push({
path: '/' + data.name,
component: data
});
});
self.router.addRoutes(_router); //全局注册都注册为路由
dfd.resolve(_router);
});
return dfd.promise();
}
main.js中的引用
var _app = app.createApp();
_app.registerGlobalComponents(['title', 'route']).done(function(){
var vue = _app.createVue();
var cxt = app.getVue().createContext();
var r = {
state: {
childs: []
},
mutations: {
childs: function(state, data){
state.childs = data;
}
},
actions: {
childs: function(state, data){
state.commit('childs', data);
}
}
}
vue.$store.registerModule('router', r);
vue.$mount('#app');
});
说明: