实现一个移动端的三级tree组件,支持多选、单选、全选、全不选、最好兼容vant组件库、用vue2写,添加测试数据和调用过程
时间: 2023-07-10 18:32:41 浏览: 125
好的,下面是一个Vue2版本的移动端三级tree组件实现,支持多选、单选、全选、全不选,并且兼容vant组件库:
```vue
<template>
<van-tree-select
v-model="checkedList"
:items="items"
:height="height"
:max-height="maxHeight"
:main-active-index.sync="mainActiveIndex"
:active-id.sync="activeId"
:border="false"
:accordion="accordion"
:selected-icon="selectedIcon"
:click-nav="clickNav"
@click-nav="onClickNav"
>
<template v-slot:content="{ item }">
<div class="tree-item">
<van-checkbox
v-model="item.checked"
:name="item.id"
@change="onChange(item)"
/>
<span>{{ item.label }}</span>
</div>
</template>
</van-tree-select>
</template>
<script>
import { TreeSelect, Checkbox } from 'vant';
import { cloneDeep } from 'lodash';
export default {
name: 'ThreeLevelTree',
components: {
VanTreeSelect: TreeSelect,
VanCheckbox: Checkbox,
},
props: {
items: {
type: Array,
required: true,
},
height: {
type: [Number, String],
default: 300,
},
maxHeight: {
type: [Number, String],
default: 300,
},
accordion: {
type: Boolean,
default: true,
},
selectedIcon: {
type: String,
default: 'success',
},
clickNav: {
type: Boolean,
default: false,
},
defaultValue: {
type: [String, Number, Array],
default: null,
},
defaultChecked: {
type: Array,
default: () => [],
},
multiple: {
type: Boolean,
default: false,
},
checkStrictly: {
type: Boolean,
default: false,
},
},
data() {
return {
checkedList: cloneDeep(this.defaultChecked),
mainActiveIndex: 0,
activeId: this.defaultValue,
};
},
watch: {
defaultValue: {
handler(val) {
this.activeId = val;
},
immediate: true,
},
defaultChecked: {
handler(val) {
this.checkedList = cloneDeep(val);
},
immediate: true,
},
},
methods: {
onClickNav({ index }) {
this.mainActiveIndex = index;
},
onChange(item) {
if (!this.multiple) {
this.checkedList = [];
}
if (item.children && !this.checkStrictly) {
this.checkChildren(item, item.checked);
this.checkParent(item);
} else {
this.checkSelf(item);
this.checkParent(item);
}
this.$emit('change', cloneDeep(this.checkedList));
},
checkSelf(item) {
const index = this.checkedList.findIndex(
(v) => v.id === item.id && v.label === item.label
);
if (item.checked && index === -1) {
this.checkedList.push(item);
} else if (!item.checked && index !== -1) {
this.checkedList.splice(index, 1);
}
},
checkChildren(item, checked) {
if (!item.children) {
return;
}
item.children.forEach((child) => {
child.checked = checked;
this.checkChildren(child, checked);
});
},
checkParent(item) {
if (!item.parent) {
return;
}
const parent = this.getItemById(item.parent);
if (!parent) {
return;
}
const checkedChildrenCount = parent.children.filter((child) => child.checked).length;
parent.checked = checkedChildrenCount === parent.children.length;
this.checkParent(parent);
},
getItemById(id, items = this.items) {
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.id === id) {
return item;
}
if (item.children) {
const result = this.getItemById(id, item.children);
if (result) {
return result;
}
}
}
return null;
},
checkAll() {
this.items.forEach((item) => {
item.checked = true;
this.checkChildren(item, true);
});
this.checkedList = cloneDeep(this.items);
this.$emit('change', cloneDeep(this.checkedList));
},
uncheckAll() {
this.items.forEach((item) => {
item.checked = false;
this.checkChildren(item, false);
});
this.checkedList = [];
this.$emit('change', []);
},
},
};
</script>
<style scoped>
.tree-item {
display: flex;
align-items: center;
}
</style>
```
上面的代码中,我们使用了vant的TreeSelect组件来实现Tree组件,并自定义了节点的内容区域。我们通过props属性接收组件的数据源,并通过data属性初始化组件的状态。在Tree组件中,我们实现了多选、单选、全选、全不选等功能,并通过事件和状态管理来实现这些功能。在组件的methods属性中,我们定义了一些辅助方法,用于实现复杂的业务逻辑。
为了测试这个组件,我们可以在父组件中引入这个组件,并传入测试数据和props属性:
```vue
<template>
<div class="container">
<three-level-tree
:items="items"
:default-checked="defaultChecked"
:multiple="true"
@change="onChange"
/>
<van-button @click="checkAll">全选</van-button>
<van-button @click="uncheckAll">全不选</van-button>
</div>
</template>
<script>
import ThreeLevelTree from './ThreeLevelTree.vue';
export default {
name: 'App',
components: {
ThreeLevelTree,
},
data() {
return {
items: [
{
id: 1,
label: '一级节点1',
children: [
{
id: 11,
label: '二级节点1-1',
children: [
{
id: 111,
label: '三级节点1-1-1',
},
{
id: 112,
label: '三级节点1-1-2',
},
],
},
{
id: 12,
label: '二级节点1-2',
children: [
{
id: 121,
label: '三级节点1-2-1',
},
{
id: 122,
label: '三级节点1-2-2',
},
],
},
],
},
{
id: 2,
label: '一级节点2',
children: [
{
id: 21,
label: '二级节点2-1',
children: [
{
id: 211,
label: '三级节点2-1-1',
},
{
id: 212,
label: '三级节点2-1-2',
},
],
},
{
id: 22,
label: '二级节点2-2',
children: [
{
id: 221,
label: '三级节点2-2-1',
},
{
id: 222,
label: '三级节点2-2-2',
},
],
},
],
},
],
defaultChecked: [
{
id: 111,
label: '三级节点1-1-1',
},
{
id: 122,
label: '三级节点1-2-2',
},
],
};
},
methods: {
onChange(val) {
console.log('选中的节点:', val);
},
checkAll() {
this.$refs.tree.checkAll();
},
uncheckAll() {
this.$refs.tree.uncheckAll();
},
},
};
</script>
```
上面的代码中,我们定义了一个父组件,包含了一个三级tree组件和两个按钮。我们给三级tree组件传入了测试数据和props属性,并监听change事件输出选中的节点。在组件中,我们通过$refs获取到三级tree组件的实例,并通过调用checkAll和uncheckAll方法实现全选和全不选功能。
最后,我们将父组件渲染到页面中:
```vue
<template>
<div id="app">
<app />
</div>
</template>
<script>
import App from './App.vue';
export default {
components: {
App,
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
```
上面的代码中,我们将App组件渲染到页面中。至此,我们就完成了一个Vue2版本的移动端三级tree组件的实现,支持多选、单选、全选、全不选,并且兼容vant组件库。
阅读全文