javascript - Vuejs复选框分组全选
问题描述
我有一个被分成组的对象数组。每个组都有自己的项目,如果选中父母,我需要选中所有子复选框,如果未选中父母,则取消选中。如果 selectAll 检查了所有组和组项目,则也应检查
我想要达到的和这个例子一样
我在这里设置了jsfiddle,这就是我到目前为止所做的。
数据
const groups = [
{
id: 1,
name: "TEST A",
items: [
{ id: 1, name: "item 1" },
{ id: 2, name: "item 2" }
]
},
{
id: 2,
name: "TEST B",
items: [
{ id: 3, name: "item 1" },
{ id: 4, name: "item 2" }
]
}
]
HTML
<div id="app">
<div>
<input type="checkbox" class="mb-2" v-model="selectAll" /> select all
<div v-for="group in groups" :key="group.id" class="mb-2">
<input
type="checkbox"
v-model="selectedGroups"
:value="group.id"
/>
<b>{{ group.name }}</b>
<c-item
v-for="item in group.items"
:item="item"
:key="item.id"
@change="onChangeItem"
:checked="selectedItems.includes(item.id)"
/>
</div>
</div>
</div>
<template id="x-item">
<div>
<input
type="checkbox"
@change="$emit('change', item.id, $event)"
:value="item.id"
:checked="checked"
/>
{{ item.name }}
</div>
</template>
JS
Vue.component('c-item', {
props: ['item', 'checked'],
template: "#x-item",
})
new Vue({
el: "#app",
data: {
selectedItems: [],
selectedGroups: [],
groups: [
{
id: 1,
name: "TEST A",
items: [
{ id: 1, name: "item 1" },
{ id: 2, name: "item 2" }
]
},
{
id: 2,
name: "TEST B",
items: [
{ id: 3, name: "item 1" },
{ id: 4, name: "item 2" }
]
}
]
},
methods: {
onChangeItem(itemId, $event) {
if ($event.target.checked) this.selectedItems.push(itemId);
else {
const index = this.selectedItems.findIndex(c => c === itemId);
if (index >= 0) this.selectedItems.splice(index, 1);
}
}
},
computed: {
selectAll: {
get() {
return this.groups
? this.selectedGroups.length == this.groups.length
: false;
},
set(value) {
let selectedGroups = [];
if (value) {
this.groups.forEach(function(item) {
selectedGroups.push(item.id);
});
}
this.selectedGroups = selectedGroups;
}
}
}
})
有人能帮我吗?先感谢您!
解决方案
通常,您可以使用递归组件解决此类问题。这个概念是构建一个对象树,并在任何节点上检查更改,然后调用更新父项和子项,并且更改将递归进行。
<template id='x-item'>
<div>
<label>
<input
type='checkbox'
:checked='item.checked'
@change='onChange($event.target.checked)'>
<span>{{ item.label }}</span>
</label>
<template v-if='item.children'>
<x-item
v-for='item in item.children'
ref='children'
:item='item'
@change='onChildChange'>
</x-item>
</template>
</div>
</template>
Vue.component('x-item', {
template: '#x-item',
props: ['item'],
methods: {
onChange(checked) {
this.item.checked = checked
this.updateParent()
this.updateChildren(checked)
},
onChildChange() {
this.item.checked = this.$refs.children
.every(child => child.item.checked)
this.updateParent()
},
updateParent() {
this.$emit('change')
},
updateChildren(checked) {
if (!this.item.children) return
this.$refs.children.forEach(child => {
child.item.checked = checked
child.updateChildren(checked)
})
}
}
})
有时递归组件可能不容易设置样式,如果形状不是动态的,您也可以进行迭代。
<div id='app'>
<template v-if='root'>
<x-item :item='root' @change='onChange'></x-item>
<div v-for='group in root.children'>
<x-item :item='group' @change='onChange'></x-item>
<div v-for='item in group.children'>
<x-item :item='item' @change='onChange'></x-item>
</div>
</div>
</template>
</div>
<template id='x-item'>
<label>
<input
type='checkbox'
:checked='item.checked'
@change='$emit("change", item, $event.target.checked)'>
<span>{{ item.name }}</span>
</label>
</template>
...
methods: {
onChange(node, checked) {
node.checked = checked
this.updateChildren(node, checked)
this.updateTree()
},
updateChildren(node, checked) {
if (!node.children) return
node.children.forEach(child => {
child.checked = checked
this.updateChildren(child, checked)
})
},
updateTree() {
(function update(node) {
if (!node.children) return
node.children.forEach(update)
node.checked = node.children.every(child => child.checked)
})(this.root)
}
}
...
推荐阅读
- c - C 从 1 到 100 的数的倍数超过 100
- arrays - 如何在 mongo db 的数组列表中添加字段
- python - 使用 python 的 tokenize 提取所有 `INDENT` 标记
- azure - 将 CodeceptJS 与 Azure DevOps 集成
- mysql - SQL中如何获取和统计表的行数
- node.js - 使用 .json() 解析返回的字符串会引发错误
- google-cloud-storage - Apache Beam 使用哪种协议从云存储中写入和读取文件,是 HTTPS 还是二进制?
- java - 从集合中删除项目时从数据库中删除项目
- clojure - edn/read 不保持序列的顺序
- python - 所有异步、协程和同步功能的装饰器?