封装ant design vue 的a-tree组件

39 篇文章 1 订阅
12 篇文章 0 订阅

封装ant design vue 的a-tree组件,不是下拉框树的组件哈!!!别看错了。

工作中某些人要求偷懒省的麻烦,想通过直接给定url就能完整渲染的。说实话,我感觉官方给的已经很好用得了,也不是啰嗦的代码,而且我这项目一个项目用了两个地方都没有。反正挺无语的吧,于是自己尝试着搞了搞,功能肯定没有官网那么全面,但是基本使用肯定是没得问题的。需要的宝贝们可以收藏一波啦。可花费了我不少心思呢!!!!

<template>
  <div>
    <a-tree
      :checkable="checkable"
      :tree-data="treeData"
      v-model="checkedKeys_"
      :expandedKeys.sync="expandedKeys_"
      :replace-fields="replaceFields"
      @select="onSelect"
      @check="onCheck"
      @expand="expand"
      :checkStrictly="checkStrictly"
    />
  </div>
  <!-- 
    组件使用实例,其中很多参数看情况使用,不是必须使用,有存在的默认值
    <PublicTree
    url="/sys/role/queryTreeList"
    :params="{}"
    :checkable="checkable"
    :checkedKeys.sync='checkedKeys'
    :expandedKeys.sync="expandedKeys"
    :checkStrictly='checkStrictly'
    @onSelect="onSelect"
    :replaceFields="{children: 'children',title: 'slotTitle',}"
    /> -->
</template>
<script>
import { getPublicSelectList } from "@/api/api.js";

export default {
  name: 'PublicTree',
  props: {
    /*树的接口地址url */
    url: {
      type: String,
      default: ''
    },
    /* 如果当前树状图接口需要参数,传params,非必填,看实际接口情况 */
    params: {
      type: Object,
      default: () => { }
    },
    /* 是否可以勾选,非必填 */
    checkable: {
      type: Boolean,
      default: true
    },
    /* replaceFields重定向字段,非必填*/
    replaceFields: {
      type: Object,
      default: () => ({
        children: 'children',
        title: 'title',
        key: 'key'
      })
    },
    /* 默认展开的key,非必填,需要通过expandedKeys.sync 来父组件获取实时值*/
    expandedKeys: {
      type: Array,
      default: () => []
    },
    /* 勾选的key数组,非必填,但是一般情况下不要在子组件修改东西,通过checkedKeys.sync可以父组件获取 */
    checkedKeys: {
      type: Array,
      default: () => []
    },
    /* true时,父子节点选中状态不再关联,非必填 */
    checkStrictly: {
      type: Boolean,
      default: false
    },
    /* 非必填,数据是否需要处理,默认后端给处理好了,这里就不要操作。没有处理的数据,修改下方对应的id和父节点id实际字段。其中需要根据哪个字段排序就使用order,默认只能数字排序。其中boot是对应着根节点id,处理数据的时候得确保存在才能正常返回数据。deel代表是否需要自己处理数据,不需要就默认使用后端的返回,此时其余配置都失效,sort表示是否需要排序,为true的时候记得填写排序对应字段order。 */
    deelTreeData: {
      type: Object,
      default: () => ({
        deel: false,
        sort: false,
        config: {
          id: 'id',
          parentId: 'parentId',
          children: 'children',
          order: 'order',
        },
        boot: 0//根部id值
      })
    },
    /* 接口如果不一样,返回的结构形式就会不一样,如何拿到对应的数据。这里就不通过对象遍历依次查找了,直接通过数组直接对应着一层一层的键。一切都通过返回的res基础上执行的,此项目默认res.result.treeList拿取对应的tree树,那么就用下面默认的形式。同理,后端返回keys数组一样同样的方法。 */
    urlPointer: {
      type: Array,
      default: () => ['result', 'treeList']
    },
    /* 如上说明。标识集合id的位置 */
    keysPointer: {
      type: Array,
      default: () => ['result', 'ids']
    }
  },
  data() {
    return {
      treeData: [],
      allTreeKeys: [],
      checkedKeys_: [],
      expandedKeys_: [],
    }
  },
  watch: {
    expandedKeys: {
      handler(newvalue, oldvalue) {
        setTimeout(() => {
          this.$nextTick(() => {
            this.expandedKeys_ = newvalue
          })
        }, 500);
      }
    },
    expandedKeys_: {
      handler(newvalue, oldvalue) {
        this.$emit('update:expandedKeys', newvalue)
      }
    },
    checkedKeys: {
      handler(newvalue, oldvalue) {
        this.$nextTick(() => {
          this.checkedKeys_ = newvalue
        })
      }
    },
    checkedKeys_: {
      handler(newvalue, oldvalue) {
        this.$emit('update:checkedKeys', newvalue)
      }
    },
  },
  created() {
    this.init()

  },
  beforeDestroy() {
    this.reset()
  },
  methods: {
    //数据树普通处理 
    treeDataNoSort(source, id, parentId, children) {
      let cloneData = JSON.parse(JSON.stringify(source))
      return cloneData.filter(father => {
        let branchArr = cloneData.filter(child => father[id] == child[parentId]);
        branchArr.length > 0 ? father[children] = branchArr : ''
        return father[parentId] == this.deelTreeData.boot // 如果第一层不是parentId=0,请自行修改
      })
      /* 
      无处理数据样式
      this.source = [
              {id:1,parentId:0,name:"一级菜单A",rank:1,order:'3'},
              {id:2,parentId:0,name:"一级菜单B",rank:1,order:'2'},
              {id:3,parentId:0,name:"一级菜单C",rank:1,order:'1'},
              {id:4,parentId:1,name:"二级菜单A-A",rank:2,order:'2'},
              {id:5,parentId:1,name:"二级菜单A-B",rank:2,order:'1'},
              {id:6,parentId:2,name:"二级菜单B-A",rank:2},
              {id:7,parentId:4,name:"三级菜单A-A-A",rank:3},
              {id:8,parentId:7,name:"四级菜单A-A-A-A",rank:4},
              {id:9,parentId:8,name:"五级菜单A-A-A-A-A",rank:5},
              {id:10,parentId:9,name:"六级菜单A-A-A-A-A-A",rank:6},
              {id:11,parentId:10,name:"七级菜单A-A-A-A-A-A-A",rank:7},
              {id:12,parentId:11,name:"八级菜单A-A-A-A-A-A-A-A",rank:8},
              {id:13,parentId:12,name:"九级菜单A-A-A-A-A-A-A-A-A",rank:9},
              {id:14,parentId:13,name:"十级菜单A-A-A-A-A-A-A-A-A-A",rank:10},
            ] */
    },
    //数据树排序处理
    treeDataBySort(source, id, parentId, children, order) {
      var compare = function (prop) {
        return function (obj1, obj2) {
          var val1 = obj1[prop];
          var val2 = obj2[prop];
          return val1 - val2 //升序
          // if (val1 < val2) {
          //   console.log('val1,val2 :>> ', val1,val2);
          //   return -1;//表示第一个参数应该排在第二个参数的前面
          // } else if (val1 > val2) {
          //   return 1;//表示第一个参数应该排在第二个参数的后面
          // } else {
          //   return 0;
          // }
        }
      }
      let cloneData = JSON.parse(JSON.stringify(source))
      return cloneData.filter(father => {
        let branchArr = cloneData.filter(child => father[id] == child[parentId]).sort(compare(order));
        branchArr.length > 0 ? father[children] = branchArr : ''
        return father[parentId] == this.deelTreeData.boot // 如果第一层不是parentId=0,请自行修改
      }).sort(compare(order));
    },
    init() {
      getPublicSelectList(this.url, this.params).then(res => {
        let data = res
        let TreeData = res
        for (const item of this.urlPointer) {
          data = data[item]
        }
        for (const item of this.keysPointer) {
          TreeData = TreeData[item]
        }
        this.treeData = data
        this.allTreeKeys = TreeData || data.map(i => i[this.replaceFields['key']])
        if (this.deelTreeData.deel) {
          if (this.deelTreeData.sort) {
            this.treeData = this.treeDataBySort(this.treeData, this.deelTreeData.config['id'], this.deelTreeData.config['parentId'], this.deelTreeData.config['children'], this.deelTreeData.config['order'])
          } else {
            this.treeData = this.treeDataNoSort(this.treeData, this.deelTreeData.config['id'], this.deelTreeData.config['parentId'], this.deelTreeData.config['children'])
          }
        }
        this.expandedKeys_ = this.expandedKeys
        this.checkedKeys_ = this.checkedKeys
      })
    },
    onSelect(selectedKeys, info) {
      this.$emit('onSelect', selectedKeys, info)
    },
    onCheck(checkedKeys, info) {
      if (this.checkStrictly) {
        this.checkedKeys_ = checkedKeys.checked;
        this.$emit('update:checkedKeys', checkedKeys.checked)
      } else {
        this.checkedKeys_ = checkedKeys
        this.$emit('update:checkedKeys', checkedKeys)
      }
    },
    expand(expandedKeys) {
      this.expandedKeys_ = expandedKeys
      this.$emit('update:expandedKeys', expandedKeys)
    },
    /* 全选,父调用子 */
    checkALL() {
      this.checkedKeys_ = this.allTreeKeys
      this.$emit('update:checkedKeys', this.allTreeKeys)
    },
    /* 取消全选,父调用子 */
    cancelCheckALL() {
      this.checkedKeys_ = []
      this.$emit('update:checkedKeys', [])
    },
    /* 展开全部 */
    expandAll() {
      this.expandedKeys_ = this.allTreeKeys
      this.$emit('update:expandedKeys', this.allTreeKeys)
    },
    /* 合并全部 */
    closeAll() {
      this.expandedKeys_ = []
      this.$emit('update:expandedKeys', [])
    },
    reset() {
      this.checkedKeys_ = []
      this.expandedKeys_ = []
    }
  },
}
</script>
<style lang='less' scoped>
</style>

注意点:

1.此组件只配置了checkedkeys  ,expendedkeys,其余的就没搞双向绑定了。

2.例子在代码里面,可以直接用

3.有些props配置如果你们拿去得稍微的对组件改改。比如urlPointer,keysPointer。这两个实际作用看代码注释,再配合代码应该看懂不是问题,其实不改组件也问题不大,只是父节点就得添加个一两行绑定了。

4.此组件默认情况下后端已经把树结构给你了,很多配置你就不需要动他了。如果你后端懒得搞就想搞你,那你就需要配置deelTreeData参数。

5.仔细看最后几个方法,包括全选,取消全选,展开全部,取消展开全部四个方法。父组件如果需要就可以直接使用。这个应该没有问题,我好像还没有验证。

6.不会有小伙伴好奇getPublicSelectList方法是什么吧?这个根据每个人项目的接口封装不同而不同的。比如我这个

const getPublicSelectList = (url,params)=>getAction(url,params);

反正兄弟们,这里根据你们代码封装的接口自己处理一个这种结构的应该问题不大 。

7.关于树结构的部分怎么自己处理可以看看这里树数据处理

8.待优化的地方肯定是有的,反正能简单则简单,想到啥就弄啥 ,发现代码中还是有点多余的部分,不过问题不大。能用不报错

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ant Design Vue 中的 A-Tree 组件提供了一个 `checkable` 属性来实现全选功能。通过将 `checkable` 属性设置为 true,将会在每个节点旁边显示一个复选框,用户可以通过勾选这些复选框来选择节点。 如果您想要实现全选功能,可以在 A-Tree 的顶层节点上添加一个全选的复选框,并通过监听 `on-check` 事件来控制所有节点的选中状态。具体实现方法如下: 1. 在 A-Tree 的根节点上添加一个全选的复选框: ```html <a-tree :checkable="true" :checked-keys="checkedKeys" @check="handleCheck"> <a-tree-node :title="rootTitle" :key="rootKey"> <!-- 全选复选框 --> <template slot="title"> <a-checkbox v-model="allChecked">全选</a-checkbox> {{ rootTitle }} </template> <!-- 树节点 --> <a-tree-node v-for="node in nodes" :title="node.title" :key="node.key"></a-tree-node> </a-tree-node> </a-tree> ``` 2. 在 Vue 实例中定义 `allChecked` 和 `checkedKeys` 变量,并在 `handleCheck` 方法中更新所有节点的选中状态: ```js data() { return { allChecked: false, // 全选状态 checkedKeys: [], // 选中的节点 key nodes: [...] // 树节点数据 } }, methods: { handleCheck(checkedKeys) { // 更新选中状态 this.checkedKeys = checkedKeys; // 如果全选复选框被勾选,则选中所有节点;否则取消所有节点的选中状态 if (this.allChecked) { this.$refs.tree.setCheckedKeys(this.nodes.map(node => node.key)); } else { this.$refs.tree.setCheckedKeys([]); } } } ``` 3. 在 A-Tree 上添加一个 `ref` 属性,以便在 Vue 实例中引用该组件: ```html <a-tree ref="tree" ...> ``` 现在,您可以通过勾选顶层树节点旁边的全选复选框来实现 A-Tree 的全选功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值