Vue多组件渲染时Radio按钮跨组件点击后选中状态丢失问题
问题根因
所有Choice组件实例内的单选按钮都硬编码了相同的name="answer"属性。HTML原生单选按钮的互斥逻辑是同一页面中name属性值完全相同的单选框属于同一互斥组,组内同一时间仅能有一个按钮处于选中状态,这个规则不受组件边界影响,因此跨组件点击单选按钮时,其他同名组内的选中状态会被自动清空。
修复方法
核心修复逻辑:给每道题对应的单选按钮组分配全局唯一的name属性值,让不同题目的单选框分属不同互斥组。以下提供两种可直接落地的实现方案,二选一即可。
方案1:父组件传入唯一标识(推荐)
利用父组件Question已有的number(题号,天然唯一)属性,作为分组标识传给子组件,拼接生成唯一name值。
- 修改父组件
Question.vue的模板部分,给Choice组件传入分组id:
<template> <div class="question-container"> <div class="question"> <h2>{{ number }}. {{ question.question }}</h2> <!-- 新增传参:把题号作为分组id传给子组件 --> <Choice :choices="question.choices" :groupId="number"/> </div> </div> </template>
父组件的script部分不需要额外修改,原有props和组件引入逻辑保持不变。
- 修改子组件
Choice.vue,接收分组id并绑定到单选框的name属性上:
<template> <div class="choice"> <div v-for="(choice, index) in choices" v-bind:key="index"> <label> <!-- 动态绑定唯一name,不同题目的组名互不重复 --> <input type="radio" :name="`answer_${groupId}`" /> <span class="label-text">{{ choice }}</span> </label> </div> </div> </template> <script> export default { name: "Choice", props: { choices: Array, // 新增接收分组id的prop groupId: { type: [Number, String], required: true } }, }; </script>
方案2:子组件内部生成唯一组名(无需父组件改动)
如果不想修改父组件传参逻辑,可以直接在Choice组件内部为每个实例生成唯一组名,Vue2中每个组件实例自带全局唯一的_uid属性(实例创建时自动递增生成,无重复),可以直接用来拼接组名。
仅需修改Choice.vue即可:
<template> <div class="choice"> <div v-for="(choice, index) in choices" v-bind:key="index"> <label> <input type="radio" :name="groupName" /> <span class="label-text">{{ choice }}</span> </label> </div> </div> </template> <script> export default { name: "Choice", props: { choices: Array, }, data() { return { // 基于组件实例唯一id生成不重复的组名 groupName: `answer_${this._uid}` } } }; </script>
补充:如果使用Vue3,实例上没有暴露
_uid,可以自己在组件创建时生成随机字符串作为组名,比如groupName:answer_${Math.random().toString(36).slice(2)}``,同样能实现唯一分组的效果。
内容的提问来源于stack exchange,提问作者devAR
相关产品推荐
相关产品推荐

