Vue3+TS如何通过defineEmits向父组件传递选中的单选框值
Vue3 + TS 单选框子父传值修复方案
你的代码无法正常传值核心是v-model约定不匹配,同时存在类型定义、模板逻辑问题,按以下方式修正即可。
现存问题清单
- 事件名不匹配:父组件通过
v-model="checked"给子组件双向绑值时,Vue3默认要求子组件抛出的更新事件名为update:modelValue,你当前写的update:arrayRadio无法被父组件的v-model识别,值自然无法同步 - 类型与默认值错误:
arrayRadio是对象数组类型,你给的默认值是空字符串,且Props类型直接写any,完全丢失TS类型校验能力 - 模板逻辑bug:所有单选框的id固定写为
html,对应label的for属性全部指向同一个id,点击选项标签无法触发对应单选框选中;用@click事件取值时机过早,容易拿到选中前的旧值 - 响应式缺失:子组件内部
selected变量初始化时直接取props的静态值,没有和父组件的状态做响应式关联
修正后完整代码
父组件
父组件核心逻辑不需要改动,只需要补全子组件的导入即可(setup语法糖下导入后自动注册,不需要写在components配置里)
<script lang="ts"> import { useField, useForm } from 'vee-validate' import { string } from 'yup' export default defineComponent({ components: {}, }) </script> <script lang="ts" setup> // 补全子组件导入 import InputRadio from './InputRadio.vue' const subtitle: string | number = 'Lorem ipsum dolor sit amet consectetur.' const { handleSubmit, errors } = useForm({ validationSchema: { checked: string().required('enter the field.'), }, initialValues: { checked: '' }, }) const { value: checked } = useField<string>('checked') const arrayRadio: { name: string; description: string }[] = [ { name: 'First', description: 'Lorem ipsum dolor sit amet consectetur.', }, { name: 'Second', description: 'Lorem ipsum dolor sit amet consectetur.', }, ] </script> <template> <main class="min-h-screen"> <div class="base-container">Content</div> <InputRadio v-model="checked" :array-radio="arrayRadio" /> </main> </template>
子组件
修正Props定义、事件名、响应式逻辑和模板id绑定问题:
<script lang="ts" setup> import { computed, toRefs } from 'vue' // 定义单选选项的TS类型,移除any interface RadioOption { name: string description: string } interface Props { subtitle?: string arrayRadio?: RadioOption[] // 增加v-model默认对应的modelValue属性,类型和父组件绑定的checked一致为string modelValue?: string } const props = withDefaults(defineProps<Props>(), { subtitle: '', // 引用类型默认值通过工厂函数返回空数组,不能写空字符串 arrayRadio: () => [], modelValue: '' }) // 修正emit事件名,匹配v-model的默认约定 const emit = defineEmits<{ (event: 'update:modelValue', value: string): void }>() const { arrayRadio, subtitle, modelValue } = toRefs(props) // 用计算属性做双向代理,不需要单独维护ref,选中值变化自动触发emit const selected = computed({ get() { return modelValue.value }, set(val: string) { emit('update:modelValue', val) } }) </script> <template> <div> <div v-for="plan in arrayRadio" :key="plan.name" class="mx-auto w-full max-w-md" > <!-- 动态绑定唯一id,保证label和输入框一一对应 --> <input :id="`radio-${plan.name}`" v-model="selected" type="radio" :value="plan.name" > <label :for="`radio-${plan.name}`">{{ plan.name }}</label> <br> </div> </div> </template>
内容的提问来源于stack exchange,提问作者Dario Marjanovic
相关产品推荐
相关产品推荐

