在vue中有3個概念很容易搞混肉津,data,computed舱沧,props妹沙,特別是我們這些原后端開發(fā)人員。
new Vue({
el: "#x",
data: { id: 1 },
props: ["id"],
computed: {
id: function () { return 3; }
}
});
測試一下熟吏,結果是props
和data
無法共存距糖,data
優(yōu)先級高于computed
玄窝;
我經(jīng)常是吧組件封裝成一個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>
效果:
一開始用的還挺嗨的悍引,直到有一次一個extend用了大量的conputed
然后這個組件對應的文檔是這樣的:
結果杯具就發(fā)生了:
var pager = new vPager({
el: "#pager",
data: {
pageSize: 10
}
});
剛才文章開頭說了恩脂,data
的優(yōu)先級是高于computed
的,所以導致pageSize的計算屬性被覆蓋了趣斤,結果可想而知俩块。
所以最后使用的時候改成了這樣:
var pager = new vPager({
el: "#pager",
created: function () {
this.pageSize = 10;
}
});
但是總感覺很不舒服
所以我決定寫一個mixin來優(yōu)化這個初始化的操作;
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];
}
}
}
}
});
這是最初的樣子,挺簡單的奋渔,經(jīng)過一段時間的使用镊逝,又增加了一些功能,最后的變成了這樣子:
(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實例的字段,并觸發(fā)init
事件玄渗; - 如果init選項為無參的
function
座菠,執(zhí)行function后使用返回值初始化Vue實例字段,并觸發(fā)init
事件藤树; - 如果init選項為有參的
function
浴滴,則會傳入一個回調(diào)函數(shù),執(zhí)行回調(diào)函數(shù)會觸發(fā)init
事件岁钓,可以在init函數(shù)中直接返回初始值也可以在回調(diào)函數(shù)中傳入初始值升略; - 為Vue添加一個函數(shù)
reInit()
,用于使用原始init選項重新初始化對象并觸發(fā)init
事件(對象存在reInit成員該功能無效)屡限; - 為Vue添加一個函數(shù)
onInit(data)
品嚣,用于使用data參數(shù)初始化對象并觸發(fā)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啊央,直接返回初始化數(shù)據(jù)眶诈,延遲觸發(fā)回調(diào)
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,延遲傳入初始化數(shù)據(jù)并觸發(fā)回調(diào)
var pager = new vPager({
el: "#pager",
init: function (callback) {
$.ajax({
... ,
context: this
}).done(function (data) {
callback({
data.pageNumber,
data.pageSize
});
});
}
});
init 事件
觸發(fā) init 事件
vm.$emit("init", { vm: vm, data: initData })
訂閱 init 事件
vm.$on("init", function(event){
event.vm ...
event.initData ...
})