1.真正理解v-model
input元素上的v-model其实是一个语法糖,其真正作用有两个:(1)创建一个props,其键为value;(2)监听input事件,改变value。键名与事件名都可以另外设置。
当定义一个组件时,v-model是绑定在input的外层的,所以需要手动实现v-model。
2.provide / inject
provide属性在祖先组件定义,可以向其所有子孙组件传递一个对象。子孙组件可以通过inject接收这些属性,达成注入。
一个简单的实现:单独的radio组件可以绑定v-model,disabled和change事件。也可以在radio-group中统一绑定。
radio-group组件
1<template> 2 <div class="control"> 3 <slot></slot> <!-- radio组件会插入其中 --> 4 </div> 5</template> 6<script> 7export default { 8 name: "XRadioGroup", 9 provide() { 10 return { 11 xRadioGroup: this //将组件本身的vue对象传递给下级 12 }; 13 }, 14 props: { 15 value: null, //v-model绑定的值 16 disabled: Boolean 17 }, 18 created() { 19 this.$on("handleChange", value => { //监听自身的handleChange事件 20 this.$emit("change", value); //触发自身的change事件 21 }); 22 } 23}; 24</script>
radio组件
1<template> 2 <label class="radio"> 3 <input type="radio" v-model="model" :name="name" :value="label" :disabled="_disabled" @change="handleChange"> 4 <slot></slot> 5 <template v-if="!$slots.default">{{label}}</template> 6 </label> 7</template> 8<script> 9export default { 10 name: "XRadio", 11 inject: { 12 //获得从祖先组件定义的xRadioGroup 13 xRadioGroup: { 14 default: "" //默认为'' 15 } 16 }, 17 props: { 18 name: String, 19 disabled: Boolean, 20 label: [String, Number, Boolean], 21 value: null //v-model绑定的值 22 //size: String 23 }, 24 computed: { 25 isGroup() { 26 return this.xRadioGroup !== ""; //是否包含与radio-group中 27 }, 28 model: { 29 get() { 30 //获取时触发 31 return this.isGroup ? this.xRadioGroup.value : this.value;//实现了在group和radio上都可以绑定v-model 32 }, 33 set(val) { 34 //赋值时触发 35 this.isGroup 36 ? this.xRadioGroup.$emit("input", val) //通过input完成双向绑定 37 : this.$emit("input", val); 38 } 39 }, 40 _disabled() { 41 return this.isGroup ? this.xRadioGroup.disabled : this.disable; 42 } 43 }, 44 methods: { 45 handleChange() { 46 this.$nextTick(() => { 47 this.$emit("change", this.model); 48 this.isGroup && this.xRadioGroup.$emit("handleChange", this.model); //如xRadioGroup存在,触发其handleChange事件 49 }); 50 } 51 } 52}; 53</script>