vue 树形控件-封装思路

发布于 2022-09-12 04:39:58 字数 2424 浏览 19 评论 0

问题:自己想封装一个树形控件,看了看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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青衫负雪 2022-09-19 04:39:58

我之前写过,参考链接: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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文