requirejs、vue、vuex、vue-route的結合使用,您認為可行嗎?


     在五一節之前和一網友討論前端技術時,對方提到vue、vue-route如果配合requirejs應用。當時的我沒有想得很明白,也沒能這位網友一個准確的回復,但我許諾於他五一研究后給他一個回復。本是一天的研究卻被我搞成了研究了一周,這拖延症。。。

閑話少數,進入正題

一、示例代碼說明

代碼結構說明:

  1. modules(存放的為組件,主要是模板與Js對象分成兩個文件來寫)
    1. route:測試子路由的組件
    2. title:就是一個簡單的顯示文字的組件
  2. app.js:核心類,提供vue的創建、以前modules組件加載的方法等
  3. chart.js:模擬的一個業務模塊
  4. index.html:頁面文件
  5. layout.css:整體樣式文件(測試require加入樣式文件)
  6. main.js:requirejs的配置文件(也是入口文件)
    丑陋的效果圖:

此示例沒有樣式,只是為了驗證require如何加載一個vue組件,以子路由的動態注入的能力,示例代碼下載

二、從.vue文件入手

      一個.vue文件可以包含模板、Js類、樣式(可以不要)等三塊。但我們通過vue的官網可以知道,vue提供了compile對象方法,可以把模板編譯成VNode。並且我們通過webpack打包后生成的文件可以看出模板與Js類是混淆在一起了。這也就說明vue的組件就是一個Js對象。如下圖所示:

三、requirejs對vue、vuex和vue-route的引入

     引入這三個都很容易,並將這三個注入到Vue對象也是相對簡單的,難道的是需要解決動態注入向vue-route實例注入路由,以及vuex的動態加入一個數據模塊的能力。好在這兩點官網都給出了解決方案:

  • vue-route如何動態注入路由
    根據官網幫助文檔說明,存在addRoutes方法,向路由實體動態注入路由
  • vuex模塊動態注入
    也是根據官網幫助文檔提示有registerModule方法實現。
  • 實現的部分代碼:
    初始化Vue對象
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
    };
}

四、如何通過require加載html和js方式的組件

從項目結構圖中可以看出在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加載組件。

五、main.js是這樣引用的

提供注冊全局組件方法

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');
});

說明:

  1. 創建App的一個實例;
  2. 注冊全局的組件:title、route;
  3. 注冊完成后創建vue實例,並且向實例的vuex注入二級路由展示的模塊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM