一、开发背景
允许用户打标签,所以会有多组单选框和多选框,每组单选框允许取消当前选中。
二、整体实现
step1:v-for渲染单选框、多选框组 step2:新建情况下,恢复每个多选框组和单选框组在用户点击后高亮的响应式;编辑情况下,还需在此基础上恢复已选中标签的高亮样式; step3:单选框绑定@click事件,判断用户是否点击已选中;
三、数据结构
1.单选数据结构
2.多选数据结构
四、实现
1.html代码
第一层v-for遍历所有数据
第二层v-for遍历该层数据结构下的单选/多选标签
<div v-for="group in queryResult" :key="group.id" class="check-box">
<!-- 标题 -->
<p class="title">{{ group.tagName }}({{ group.singleChoice ? '单选' : '多选' }})</p>
<!-- 单选框组 -->
<el-radio-group v-if="group.singleChoice" v-model="selectedRadios[group.id]" size="mini">
<!-- v-for遍历当前单选框组下的单选标签 -->
<el-radio v-for="child in group.children" :key="child.id" :label="child.id" @click.native.prevent="clickItem(child.id, group.id)" border>
{{ child.tagName }}
</el-radio>
</el-radio-group>
<!-- 多选框组 -->
<el-checkbox-group v-else v-model="selectedCheckboxes[group.id]" size="mini">
<!-- v-for遍历当前多选框组下的多选标签 -->
<el-checkbox v-for="child in group.children" class="checkbox-info" :key="child.id" :label="child.id" border>
{{ child.tagName }}
</el-checkbox>
</el-checkbox-group>
</div>
2.js代码
1.准备双向绑定数据
data() {
return {
queryResult: [], // 从后端获取的数据
selectedRadios: {},// 单选选中数据
selectedCheckboxes: {},// 多选选中数据
};
},
2.恢复用户点击时的响应及编辑态时恢复高亮情况,我封成了一个函数
以当前的标签独有的不重复的id为单选标签和多选标签的key及label
queryResults.forEach部分代码遍历 queryResults
数组,对于每个 group
,如果它是一个单选组(group.singleChoice
为真),则将 selectedRadios
对象中对应的 group.id
设置为 null
,表示当前没有选中任何子项。如果它是一个多选组,则在 selectedCheckboxes
对象中创建一个新的空数组,用于存储被选中的子项的 ID。
if (isEdit) 部分:
- 如果是单选组,查找
group.children
数组中child.old
为真的子项(表示该子项在之前的状态中是被选中的)。如果找到了这样的子项,就将selectedRadios
对象中对应的group.id
设置为该子项的 ID;如果没有找到,则保持为null
。 - 如果是多选组,使用
filter
方法筛选出group.children
数组中所有child.old
为真的子项,然后使用map
方法将这些子项的 ID 提取出来,并将结果数组赋值给selectedCheckboxes
对象中对应的group.id
。
processQueryResults(queryResults, isEdit) {
// 恢复用户点击时的数据响应式
queryResults.forEach((group) => {
if (group.singleChoice) {
// 单选
this.$set(this.selectedRadios, group.id, null);
} else {
// 多选
this.$set(this.selectedCheckboxes, group.id, []);
}
});
// 如果是编辑态要恢复高亮样式
if (isEdit) {
queryResults.forEach((group) => {
if (group.singleChoice) {
// 单选
let foundChild = group.children.find((child) => child.old);
this.selectedRadios[group.id] = foundChild ? foundChild.id : null;
} else {
// 多选
this.selectedCheckboxes[group.id] = group.children.filter((child) => child.old).map((child) => child.id);
}
});
}
},
调用
success(res) {
_this.queryResult = res;
if (originalSearch) {
// 接口数据输入到processQueryResults中恢复响应式-第一个参数是数据,第二个参数用于判断是否编辑情况
_this.processQueryResults(_this.queryResult, true);
}
},
3.单选框绑定@click事件,判断用户是否点击已选中;
@click.native.prevent="clickItem(child.id, group.id)"跟踪当前点击的id
检查 selectedRadios
对象中 groupId
对应的值是否等于 childId
。如果是,那么说明当前这个“子项”已经被选中。如果“子项”已经被选中(即 this.selectedRadios[groupId] === childId
为真),则使用 this.$set
方法(用于确保响应式地更新对象属性)将 groupId
对应的值设置为 null
,从而取消选中该“子项”。
如果“子项”当前没有被选中(即 this.selectedRadios[groupId] !== childId
或 this.selectedRadios[groupId]
不存在),则使用 this.$set
方法将 groupId
对应的值设置为 childId
,从而将该“子项”设置为选中状态。
clickItem(childId, groupId) {
if (this.selectedRadios[groupId] === childId) {
// 如果当前已选中,则取消选中
this.$set(this.selectedRadios, groupId, null);
} else {
// 否则设置为选中
this.$set(this.selectedRadios, groupId, childId);
}
},
五、参考资料
1.element-UI的单选框怎么在已选中的情况下,再次点击取消选中:segmentfault.com/q/101000001…
六、注意
queryResults.forEach(group => {
if (group.singleChoice) {
// 这种写法是不行的,因为没有排除undefined情况
this.selectedRadios[group.id] = group.children.find(child => child.old).id || null;