vue 树形控件-封装思路
问题:自己想封装一个树形控件,看了看element-ui的源码有点麻烦(mei,kan,ming,bai)直接放弃了,目前组件递归没有问题,点击有子集的复选框后所有子集的checked可以跟着改变,但是状态不变,加上checkbox后就感觉懵逼了
目标:1.实现全选 2.查询 3.删除
有大神可以提供具体点的思路吗
<template><li class="tree-item">
<span @click="handlerToggle">
<em v-if="hasChild" class="icon">{{open ? '-' : '+'}}</em>
<em v-if="!hasChild" class="icon file-text"></em>
</span>
<input type="checkbox" v-model="data.checked" :value="data.id" @click="checkedChange(data,level)">
<span>{{ data.name }}</span>
<ul v-show="open" v-if="hasChild">
<tree-item v-for="(item, index) in data.list" :data="item" :key="index" :level="level+1"></tree-item>
</ul>
</li>
</template>
<script>
export default {
name: 'TreeItem',
props: {
data: {
type: [Object, Array],
required: true
},
level: {
type: Number,
default: 0
}
},
data() {
return {
open: false, // 是否展开
checkedArr: []
}
},
computed: {
// 是否有下一级
hasChild () {
if (this.data.list && this.data.list.length ) {
// console.log(1)
}
return this.data.list && this.data.list.length
}
},
methods: {
// 展开收缩
handlerToggle () {
if (this.hasChild) {
this.open = !this.open
}
},
// 本层数据添加checked
addChecked (obj) {
if (!obj.hasOwnProperty('checked')) {
obj.checked = false
}
return obj
},
// 每个多选框状态改变
checkedChange (data, level) {
if (data.list && data.list.length > 0) {
this.recurrenceCheckedChange(data);
} else {
data.checked = !data.checked;
}
},
// 递归修改多选框状态改变
recurrenceCheckedChange (data) {
data.list.forEach((item) => {
item.checked = !item.checked;
if (item.list && item.list.length > 0 ) {
this.recurrenceCheckedChange(item)
}
})
}
},
watch: {
},
created () {
},
mounted () {
this.addChecked(this.data);
}
}
</script>
<style>
.tree-item {
margin-top: 10px;
}
.tree-item ul {
margin-left: 22px;
}
em.icon {
display: inline-block;
width: 15px;
background-repeat: no-repeat;
cursor: pointer;
}
</style>
回答
我之前写过,参考链接:https://juejin.im/post/684490...
<template> <el-select
v-model="dataArr"
:multiple="multiple"
filterable
:placeholder="placeholder"
:disabled="disabled"
:collapse-tags="collapseTags"
@remove-tag="handleTagChange"
@change="handleTagChange"
@visible-change="handleOptionHidden"
:filter-method="handleSelectFilter"
class="hi-input">
<el-option value="0"
class="hidden">
</el-option>
<el-checkbox
v-if="selectAll"
v-model="checked"
@change="handleSelectAll"
class="select-all">
Select All
</el-checkbox>
<el-tree
ref="tree"
:data="options"
node-key="key"
show-checkbox
:default-checked-keys="selectedData"
@check="handleCheckChange"
:filter-node-method="handleTreeFilter"
:props="defaultProps">
</el-tree>
</el-select>
</div>
</template>
<script>
export default {
data() {
return {
dataArr: [],
selectedData: [],
selectedItem: [],
defaultProps: {
children: 'children',
label: 'label'
},
checked: false
};
},
props: {
dataList: {
type: Array,
default: function() {
return [];
}
},
options: {
type: Array,
default: function() {
return [];
}
},
placeholder: {
type: String,
default: 'Select'
},
selectAll: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: true
},
title: {
type: String
},
collapseTags: {
type: Boolean,
default: true
}
},
watch: {
selectedData: function(newValue) {
this.$nextTick(() => { this.dataArr = this.handleDataTransform(newValue, 'key', 'label'); });
},
dataList: {
immediate: true,
handler(newValue) {
this.selectedData = newValue;
this.$nextTick(() => this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedData));
this.cancelSelectAll();
}
}
},
methods: {
handleSelectFilter: function(val) {
this.$refs.tree.filter(val);
},
handleTreeFilter: function(value, data) {
if (!value) return true;
return data.label.toUpperCase().indexOf(value.toUpperCase()) !== -1;
},
// 下拉框收起时再触发
handleOptionHidden: function(item) {
// 处理选中内容没变的情况
if (item) {
this.selectedItem = [...this.selectedData];
} else {
if (!this.$util.isEqual(this.selectedItem, this.selectedData)) {
this.handleUpdate(this.selectedData);
}
// 为了处理搜素关键字输入后,移出下拉框焦点后 options 恢复数据
this.$refs.tree.filter('');
}
},
handleTagChange: function() {
this.selectedData = this.handleDataTransform(this.dataArr, 'label', 'key');
this.$refs.tree.setCheckedKeys(this.selectedData);
this.handleUpdate(this.selectedData);
},
handleUpdate: function(item) {
this.$emit('update:dataList', item);
this.$emit('change-field');
this.cancelSelectAll();
},
handleCheckChange: function() {
this.selectedData = this.$refs.tree.getCheckedKeys().filter(_ => _);
// 这里是为了通过表单验证的处理
this.$emit('update:dataList', this.selectedData);
this.cancelSelectAll();
},
handleDataTransform: function(source, key, value) {
return this.options.map(_ => {
let arr = [];
if (_.children) {
arr = source.map(item => this.$business.getNameById(
_.children,
item,
key,
value
));
} else if (source.includes(_[key])) {
arr = [_[value]];
}
return arr.filter(item => item);
}).reduce((acc, cur) => {
return acc.concat(cur);
}, []);
},
cancelSelectAll() {
// 处理全选
if (this.selectAll && (this.selectedData.length !== this.options.length)) {
this.checked = false;
}
},
handleSelectAll() {
this.selectedData = this.checked ? this.options.map(_ => _.key) : [];
this.$refs.tree && this.$refs.tree.setCheckedKeys(this.selectedData);
}
}
};
</script>
<style lang="less" scoped>
</style>
以上是 vue 树形控件-封装思路 的全部内容, 来源链接: utcz.com/a/43694.html