vue 树形控件-封装思路

问题:自己想封装一个树形控件,看了看element-ui的源码有点麻烦(mei,kan,ming,bai)直接放弃了,目前组件递归没有问题,点击有子集的复选框后所有子集的checked可以跟着改变,但是状态不变,加上checkbox后就感觉懵逼了
目标:1.实现全选 2.查询 3.删除
有大神可以提供具体点的思路吗
image.png

<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>
阅读 229
评论
    1 个回答

    我之前写过,参考链接: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>
      撰写回答

      登录后参与交流、获取后续更新提醒

      相似问题
      推荐文章