vue elementUI select树性选择器

卡顿假死
服务端返回全部数据时,有两三千条,渲染全量的tree组件时前端直接卡死,排查发现业务数据大部分子节点的量级在万以上。页面卡死,改成懒加载模式后.树形选择器使用了vue-easy-tree

npm install @wchbrad/vue-easy-tree

vue-easy-tree这个插件的具体使用看这个文章
组件中使用

import VueEasyTree from "@wchbrad/vue-easy-tree";
// 样式文件,可以根据需要自定义样式或主题
import "@wchbrad/vue-easy-tree/src/assets/index.scss"
export default {
  components: {
    VueEasyTree
  }
}

此处只演示了几条数据,vue-easy-tree作为虚拟滚动时,必须给个固定高度和node-key
vue elementUI select树性选择器_第1张图片

<template>
  <div>
    <el-select
      v-model="value"
      multiple
      v-bind="$attrs"
      collapse-tags
      style="width:100%"
      popper-class="treeDown"
      @remove-tag="removeTag"
    >
    <el-option value="" />
        <vue-easy-tree
          ref="treeOption"
          :node-key="nodeKey"
          height="280px"
          :data="options"
          show-checkbox
          :props="defaultProps"
          :default-checked-keys="defaultCheckNodes"
          :check-strictly="true"
          @check="checkNode"
          @check-change="checkChange"
        ></vue-easy-tree>
    </el-select>
  </div>
</template>
<script>
export default {
  name: 'DepSelector',
  props: {
    // 可用选项的数组
    options: {
      type: Array,
      default: () => []
    },
    // 配置选项
    defaultProps: {
      type: Object,
      default: () => ({
        // 属性值为后端返回的对应的字段名
        children: 'children',
        label: 'name',
      })
    },
    nodeKey: {
      type: String,
      default: () => {
        return 'id'
      },
    },
    // 默认勾选的节点
    defaultCheckNodes: {
      type: Array, // 已经分配的资源
      default: () => {
        return []
      },
    },
  },
  data() {
    return {
      // 文本框中的标签
      value: [],
       // 输入框回显值
       treeLabel: [],
      // 勾选数据的完整节点
      allTreeList: [],
    }
  },
  watch:{
    defaultCheckNodes:{
      handler(val) {
      //监听父组件传给子组件默认绑定的值
      this.$nextTick(()=>{
      //获取当前选中的节点
        this.allTreeList = this.$refs.treeOption.getCheckedNodes()
        //获取选中的keys数组
        this.treeLabel = this.$refs.treeOption.getCheckedKeys()
        //获取选中值的name,赋给select选择框
        this.value = this.allTreeList.map(item => {
          return item.name
        })
        this.$emit('input', this.value)
      })
      },
      deep:true,
      immediate: true
    }
  },
  methods: {
    reset() {
      this.$refs.treeOption.setCheckedKeys([])
    },
    // 删除tag时,
    removeTag(val) {
      // 取消勾选
      // console.log(this.nodeKey)
      //移除的tag永远是选中节点的第一个
      const treeOption = this.$refs.treeOption
      treeOption.setChecked(this.treeLabel[0], false, false)
    },
    // 勾选节点触发事件
    checkNode(currentObj, treeStatus) {
      // 重新给控件赋值
      this.hanleCheck(currentObj, treeStatus, 'treeOption')
    },
    hanleCheck(data, node, treeName) {
      const _this = this
      // 获取当前节点是否被选中
      const children = _this.defaultProps.children
      const isChecked = _this.$refs[treeName].getNode(data).checked
      // 如果当前节点被选中,则遍历下级子节点并选中,如果当前节点取消选中,则遍历下级节点并取消
        // 判断该节点是否有下级节点,如果有那么遍历设置下级节点为选中
      if(Array.isArray(data[children]) && data[children].length) {
       setChildreChecked(data[children],isChecked)
        // let list =  setChildreChecked(data[children],true)
        // _this.$refs[treeName].setCheckedKeys([...new Set([...node.checkedKeys,...list])])
      }
      _this.$nextTick(()=>{
      //组件赋值更新结束才能获取到选中的节点
        this.allTreeList = this.$refs.treeOption.getCheckedNodes()
        this.value = this.allTreeList.map(item => {
          return item.name
        })
        this.treeLabel = this.$refs.treeOption.getCheckedKeys()
        this.$emit('input', this.value)
      })
      function setChildreChecked(node,isChecked) {
      //  return node.reduce((arr,item)=>{
      //     if(Array.isArray(item[children])&&item[children].length) {
      //       arr.psuh(...setChildreChecked(item[children]))
      //     }
      //     arr.push(item[_this.nodeKey])
      //     return arr
      //   },[])
        node.forEach((item) => {
          item[children] &&
            item[children].length > 0 &&
            setChildreChecked(item[children], isChecked)
          // 修改勾选状态
          _this.$refs[treeName].setChecked(item[_this.nodeKey], isChecked)
        })
      }
    },
    //数据变更时触发
    checkChange(data, checked, indeterminate) {
      // console.log(data, checked,indeterminate,"checkChange");
      // this.allTreeList = this.$refs.treeOption.getCheckedNodes()
      // this.value = this.allTreeList.map(item => {
      //   return item.name
      // })
      // // 输入框回显
      // this.treeLabel = this.$refs.treeOption.getCheckedKeys()
      // console.log(this.allTreeList,this.treeLabel );
      // // 重新给控件赋值
      // this.$emit('input', this.value)
    },
  },
}
</script>

下面树形组件根据前面树形组件勾选的,下组件禁止勾选前面组件未勾选的数据.
效果
前面组件选中
vue elementUI select树性选择器_第2张图片
下面组件勾选
vue elementUI select树性选择器_第3张图片

  watch: {
  //orgTypeCodes 前面组件勾选的数据
    'orgTypeCodes': {
      handler(newVal, oldVal) {
      //this.$refs.selectTree 组件的ref实例
        if (this.$refs.selectTree && newVal) {
        //this.allTreeList = this.$refs.treeOption.getCheckedNodes()勾选的节点
          const allTreeList = cloneDeep(this.$refs.selectTree.allTreeList)
          //克隆一份初始化树形数据options
          const list = cloneDeep(this.treeMeta)
          this.fn(list, allTreeList)
          //下面组件的options等于这个返回的数据
          this.optionsMetaAll = list
        }
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    fn(val, list = []) {
      val.forEach(item => {
      //将所有数据disabled置为true
        item.disabled = true
        //然后找出选中节点中是否有当前item
        const e = list.find(it => it.code === item.code)
        //如果有就把当前数据disabled置为false
        e && (item.disabled = false)
        //再判断是否有子节点 有则循环递归
        if (Array.isArray(item.childrenOrgs) && item.childrenOrgs.length) {
          this.fn(item.childrenOrgs, list)
        }
      })
    }
  }

你可能感兴趣的:(vue.js,elementui,javascript)