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组件
<template>
<div class="control">
<slot></slot> <!-- radio组件会插入其中 -->
</div>
</template>
<script>
export default {
name: "XRadioGroup",
provide() {
return {
xRadioGroup: this //将组件本身的vue对象传递给下级
};
},
props: {
value: null, //v-model绑定的值
disabled: Boolean
},
created() {
this.$on("handleChange", value => { //监听自身的handleChange事件
this.$emit("change", value); //触发自身的change事件
});
}
};
</script>
radio组件
<template>
<label class="radio">
<input type="radio" v-model="model" :name="name" :value="label" :disabled="_disabled" @change="handleChange">
<slot></slot>
<template v-if="!$slots.default">{{label}}</template>
</label>
</template>
<script>
export default {
name: "XRadio",
inject: {
//获得从祖先组件定义的xRadioGroup
xRadioGroup: {
default: "" //默认为''
}
},
props: {
name: String,
disabled: Boolean,
label: [String, Number, Boolean],
value: null //v-model绑定的值
//size: String
},
computed: {
isGroup() {
return this.xRadioGroup !== ""; //是否包含与radio-group中
},
model: {
get() {
//获取时触发
return this.isGroup ? this.xRadioGroup.value : this.value;//实现了在group和radio上都可以绑定v-model
},
set(val) {
//赋值时触发
this.isGroup
? this.xRadioGroup.$emit("input", val) //通过input完成双向绑定
: this.$emit("input", val);
}
},
_disabled() {
return this.isGroup ? this.xRadioGroup.disabled : this.disable;
}
},
methods: {
handleChange() {
this.$nextTick(() => {
this.$emit("change", this.model);
this.isGroup && this.xRadioGroup.$emit("handleChange", this.model); //如xRadioGroup存在,触发其handleChange事件
});
}
}
};
</script>