Vue 中雙向繫結 Vs 單向資料流

GeekQiaQia發表於2019-04-07

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>
複製程式碼

相關文章