簡書html
在vue中有3個概念很容易搞混,data,computed,props,特別是咱們這些原後端開發人員。vue
new Vue({ el: "#x", data: { id: 1 }, props: ["id"], computed: { id: function () { return 3; } } });
測試一下,結果是props
和data
沒法共存,data
優先級高於computed
;ajax
我常常是吧組件封裝成一個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功能
object
,則使用init選項的值初始化Vue實例的字段,並觸發init
事件;function
,執行function後使用返回值初始化Vue實例字段,並觸發init
事件;function
,則會傳入一個回調函數,執行回調函數會觸發init
事件,能夠在init函數中直接返回初始值也能夠在回調函數中傳入初始值;reInit()
,用於使用原始init選項從新初始化對象並觸發init
事件(對象存在reInit成員該功能無效);onInit(data)
,用於使用data參數初始化對象並觸發init
事件;要關閉init功能也能夠在初始化時將init:undefined
,爲此須要專門寫一個合併選項策略
Vue.config.optionMergeStrategies.init = function (parent, child) { return child; }
策略比較粗暴,直接讓子選項覆蓋父選項;
除了最初的初始化屬性的功能之外還支持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 } } });
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 } } });
var pager = new vPager({ el: "#pager", init: function (callback) { $.ajax({ ... , context: this }).done(function (data) { callback({ data.pageNumber, data.pageSize }); }); } });
觸發 init 事件
vm.$emit("init", { vm: vm, data: initData })
訂閱 init 事件
vm.$on("init", function(event){ event.vm ... event.initData ... })