Vue 學習筆記 — 組件初始化

簡書html

在vue中有3個概念很容易搞混,data,computed,props,特別是咱們這些原後端開發人員。vue

new Vue({
    el: "#x",
    data: { id: 1 },
    props: ["id"],
    computed: {
        id: function () { return 3; }
    }
});

測試一下,結果是propsdata沒法共存,data優先級高於computedajax

我常常是吧組件封裝成一個extend來使用的,好比這樣:後端

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <script src="js/vue2.2.6.js"></script>
    <script src="js/vCheckBox.js"></script>
</head>
<body>
    <input type="checkbox" id="test1" />
    <script>
        var test1 = new vCheckBox({
            el: "#test1",
            data: {
                text: "測試多選框"
            }
        });
    </script>
</body>
</html>

效果:app

一開始用的還挺嗨的,直到有一次一個extend用了大量的conputed函數

而後這個組件對應的文檔是這樣的:測試

結果杯具就發生了:優化

var pager = new vPager({
    el: "#pager",
    data: {
        pageSize: 10
    }
});

剛纔文章開頭說了,data的優先級是高於computed的,因此致使pageSize的計算屬性被覆蓋了,結果可想而知。
因此最後使用的時候改爲了這樣:this

var pager = new vPager({
    el: "#pager",
    created: function () {
        this.pageSize = 10;
    }
});

可是總感受很不舒服code

因此我決定寫一個mixin來優化這個初始化的操做;

var pager = new vPager({
    el: "#pager",
    init: {
        pageSize: 10
    }
});

我但願達到這樣的效果,不管是data或者computed均可以被賦值

vue.mixin({
    created: function () {
        var init = this.$options.init;
        if (typeof init === "object") {
            for (var key in init) {
                if (init.hasOwnProperty(key) && this.hasOwnProperty(key)) {
                    this[key] = init[key];
                }
            }
        }
    }
});

這是最初的樣子,挺簡單的,通過一段時間的使用,又增長了一些功能,最後的變成了這樣子:

(function (vue) {
    if (vue == null) return;
    vue.config.optionMergeStrategies.init = function (parent, child) { return child; }
    vue.mixin({
        beforeCreate: function () {
            var opt = this.$options;
            if (opt.init === undefined) return;
            if (opt.created == null) {
                opt.created = [];
            }
            var me = this;

            opt.created.push(init);
            var hasOnInit = "onInit" in opt.methods;
            if (!hasOnInit) {
                opt.methods.onInit = initCallback;
            }
            if ("reInit" in opt.methods === false) {
                opt.methods.reInit = init;
            }
            //--- function ---
            function initCallback(data) {
                if (hasOnInit && typeof me.onInit === "function") {
                    me.onInit.apply(me, arguments);
                }
                setData(data);
                me.$emit("init", { vm: me, data: data });
            }

            function setData(data) {
                if (typeof data === "object") {
                    for (var key in data) {
                        if (data.hasOwnProperty(key) && key in me) {
                            me[key] = data[key];
                        }
                    }
                }
            }

            function init() {
                var initData = me.$options.init;
                var callback = initCallback;
                if (typeof initData === "function") {
                    if (initData.length > 0) {
                        initData = initData.call(me, callback);
                        callback = null;
                    } else {
                        initData = initData.call(me);
                    }
                }

                setData(initData);
                callback && callback(initData);
            }
        }
    });
})(window.Vue);

這是個全局的mixin,爲每一個存在init選項的Vue實例添加init功能

init功能:

  • 若是init選項爲object,則使用init選項的值初始化Vue實例的字段,並觸發init事件;
  • 若是init選項爲無參的function,執行function後使用返回值初始化Vue實例字段,並觸發init事件;
  • 若是init選項爲有參的function,則會傳入一個回調函數,執行回調函數會觸發init事件,能夠在init函數中直接返回初始值也能夠在回調函數中傳入初始值;
  • 爲Vue添加一個函數reInit(),用於使用原始init選項從新初始化對象並觸發init事件(對象存在reInit成員該功能無效);
  • 爲Vue添加一個函數onInit(data),用於使用data參數初始化對象並觸發init事件;
關閉init功能

要關閉init功能也能夠在初始化時將init:undefined,爲此須要專門寫一個合併選項策略

Vue.config.optionMergeStrategies.init = function (parent, child) { return child; }

策略比較粗暴,直接讓子選項覆蓋父選項;
除了最初的初始化屬性的功能之外還支持init爲function的狀況:

init 爲無參的`function
var pager = new vPager({
    el: "#pager",
    init: function() {
        var p = location.search.slice(1).split(',');
        return {
            pageNumber: p[0] || 1,
            pageSize: p[1] || 20
        }
    }
});
init 爲有參的`function,直接返回初始化數據,延遲觸發回調
var pager = new vPager({
    el: "#pager",
    init: function (callback) {
        $.ajax({
            ... ,
            context: this
        }).done(function (data) {
            this.pageNumber = data.pageNumber;
            this.pageSize = data.pageSize;
            callback();
        });
        return {
            pageNumber: 1,
            pageSize: 20
        }
    }
});
init 爲有參的`function,延遲傳入初始化數據並觸發回調
var pager = new vPager({
    el: "#pager",
    init: function (callback) {
        $.ajax({
            ... ,
            context: this
        }).done(function (data) {
            callback({
                data.pageNumber,
                data.pageSize
            });
        });
    }
});
init 事件

觸發 init 事件

vm.$emit("init", { vm: vm, data: initData })

訂閱 init 事件

vm.$on("init", function(event){
    event.vm ...
    event.initData ...
})
相關文章
相關標籤/搜索