Vue 中雙向繫結Vs 單向資料流;
Vue中資料時單向資料流、而不是雙向繫結;,Vue 的雙向繫結不過是語法糖;
Object.defineProperty是用來做響應式資料更新的,而不是雙向繫結;
屬性傳遞、事件回撥的方式做資料更新;VS v-model資料雙向繫結;
事實上V-model 在編譯後的形式,就是通過父元件的屬性傳遞以及事件回撥的方式做的資料更新;
當一個元件需要多個屬性的雙向繫結的時候: 通過 .sync 的方式對其他屬性,做雙向資料繫結;
引用唐老師的示例程式碼
index.vue 中如下所示; 引入子元件 PersonalInfo ; 在data 資料中,定義了一個物件phoneInfo{}; zipCode:"";
1.在template 中第一個PersonalInfo 通過v-model 和 .sync 分別對兩個屬性進行了雙向資料繫結;
2.在第二個PersonalInfo 通過傳遞屬性和事件回撥的方式實現資料的響應式更新;
<template>
<div>
<PersonalInfo v-model="phoneInfo" :zip-code.sync="zipCode" />
<PersonalInfo
:phone-info="phoneInfo"
:zip-code="zipCode"
@change="val => (phoneInfo = val)"
@update:zipCode="val => (zipCode = val)"
/>
phoneInfo: {{ phoneInfo }}
<br />
zipCode: {{ zipCode }}
</div>
</template>
<script>
import PersonalInfo from "./PersonalInfo";
export default {
components: {
PersonalInfo
},
data() {
return {
phoneInfo: {
areaCode: "+86",
phone: ""
},
zipCode: ""
};
}
};
</script>
複製程式碼
在子元件PersonInfo.vue 中;
在model 中宣告 繫結屬性 model: { prop: "phoneInfo", // 預設 value event: "change" // 預設 input }, 通過父元件屬性傳值、子元件事件回撥實現資料更新;
<template>
<div>
<select
:value="phoneInfo.areaCode"
placeholder="區號"
@change="handleAreaCodeChange"
>
<option value="+86">+86</option>
<option value="+60">+60</option>
</select>
<input
:value="phoneInfo.phone"
type="number"
placeholder="手機號"
@input="handlePhoneChange"
/>
<input
:value="zipCode"
type="number"
placeholder="郵編"
@input="handleZipCodeChange"
/>
</div>
</template>
<script>
export default {
name: "PersonalInfo",
model: {
prop: "phoneInfo", // 預設 value
event: "change" // 預設 input
},
props: {
phoneInfo: Object,
zipCode: String
},
methods: {
handleAreaCodeChange(e) {
this.$emit("change", {
...this.phoneInfo,
areaCode: e.target.value
});
},
handlePhoneChange(e) {
this.$emit("change", {
...this.phoneInfo,
phone: e.target.value
});
},
handleZipCodeChange(e) {
this.$emit("update:zipCode", e.target.value);
}
}
};
</script>
複製程式碼
改寫以上程式碼,使之實現校驗,手機號碼校驗,只需要傳遞對應校驗規則,提示屬性即可;如下:
父元件Index.vue 傳遞屬性::valide;message:
<template>
<div>
<PersonalInfo
v-model="phoneInfo"
required
:validate="validate"
message="手機號為空或不合法"
:zip-code.sync="zipCode"
/>
phoneInfo: {{ phoneInfo }}
<br />
zipCode: {{ zipCode }}
</div>
</template>
<script>
import PersonalInfo from "./PersonalInfo";
export default {
components: {
PersonalInfo
},
data() {
return {
phoneInfo: {
areaCode: "+86",
phone: ""
},
zipCode: ""
};
},
methods: {
validate(phone = "") {
return phone && /^1[0-9]{10}$/.test(phone);
}
}
};
</script>
複製程式碼
子元件personal.VUE ;通過watch phoneInfo.phone; 觸發回撥函式;觸發父元件傳遞的函式校驗規則,通過v-if 來顯示校驗提示資訊;
<template>
<div>
<select
:value="phoneInfo.areaCode"
placeholder="區號"
@change="handleAreaCodeChange"
>
<option value="+86">+86</option>
<option value="+60">+60</option>
</select>
<input
:value="phoneInfo.phone"
type="number"
placeholder="手機號"
@input="handlePhoneChange"
/>
<input
:value="zipCode"
type="number"
placeholder="郵編"
@input="handleZipCodeChange"
/>
<br />
<span v-if="showMessage" style="color: red;">{{ message }}</span>
</div>
</template>
<script>
export default {
name: "PersonalInfo",
model: {
prop: "phoneInfo", // 預設 value
event: "change" // 預設 input
},
props: {
phoneInfo: Object,
zipCode: String,
required: Boolean,
message: String,
validate: Function
},
data() {
return {
showMessage: false
};
},
watch: {
"phoneInfo.phone": function(val) {
this.handleValidate(val);
}
},
methods: {
handleAreaCodeChange(e) {
this.$emit("change", {
...this.phoneInfo,
areaCode: e.target.value
});
},
handlePhoneChange(e) {
this.$emit("change", {
...this.phoneInfo,
phone: e.target.value
});
},
handleZipCodeChange(e) {
this.$emit("update:zipCode", e.target.value);
},
handleValidate(val) {
const res = this.validate(val);
this.showMessage = !res;
}
}
};
</script>
複製程式碼