一颗懒加载、可勾选、可查询的树组件

效果图:

代码:

<template>
   <div
    name="input-tree"
    id="input-tree"
  > 
    <div class="el-input el-input--suffix">
      <input
        type="text"
        placeholder="请选择"
        class="el-input__inner"
        @click="handleIconClick"
        v-if="theSelected.all.length===0"
        :disabled="theEdit"
        :readonly="true"
      >
      <div
        v-else
        class="el-textarea__inner"
        @click.stop="handleIconClick"
      >
        <!-- 选中的标签 -->
        <el-tag
          v-for="item in theSelected.all"
          :key="item.albumid"
          size="small"
          type="success"
          :closable="true"
          @close="deleteTag($event, item)"
          disable-transitions
        >
          <el-tooltip
            :content="item.label"
            placement="bottom-start"
          >
            <span>{{ item.label }}</span>
          </el-tooltip>
        </el-tag>
      </div>
      <span class="el-input__suffix">
        <span class="el-input__suffix-inner">
          <span
            :class="['hand', 'el-icon-arrow-' + iconClass]"
            @click.stop="handleIconClick"
          ></span>
        </span>
      </span>
    </div>
    <div
      class="el-select-dropdown el-popper"
      :style="{ display:popperDisplay, width: popperWidth}"
    >
      <div class="el-dialog__header">
        <slot name="title">
          <span class="el-dialog__title">{{ theTitle }}</span>
          <el-input
            placeholder="输入关键字进行过滤"
            prefix-icon="el-icon-search"
            v-model="filterText">
          </el-input>
        </slot>
        <button
          type="button"
          class="el-dialog__headerbtn"
          aria-label="Close"
          @click="handleClose"
        >
          <i class="el-dialog__close el-icon el-icon-close"></i>
        </button>
      </div>
      <el-scrollbar
        :style="'height:250px'"
        class="el-scrollbar--hidden"
      >
        <el-tree
         v-show="!filterText"
          ref="combotree"
          node-key="theId"
          show-checkbox
          check-strictly
          :lazy="true"
          :highlight-current="true"
          :props="theTreeConfig.defaultProps"
          :default-expanded-keys="theTreeConfig.defaultExpandedKeys"
          :load="loadTheTree"
          :filter-node-method="filterNode"
          @check-change="handleCheckChange"
        >
           <span slot-scope="{ data }">
            <i class="tree-icon primary" v-if="data.theType == '1'"></i>
            <i class="iconfont icon-edit-user" v-else-if="data.theType =='2'" style="color:#088fff"></i>
            <i class="iconfont icon-mine" v-else-if="data.theType =='3'" style="color:#088fff"></i>
            <i v-else class="tree-icon primary"></i>
            <span>{{data.label}}</span>
          </span>
        </el-tree>
        <!-- 查询机构显示 -->
        <div v-show="filterText">
          <el-checkbox-group v-model="checkList" @change="handleCheckAllChange">
            <el-checkbox :label="item.theId" v-for="item in searchUnitlist" :key="item.index">
              <i class="tree-icon primary" v-if="item.theType == '1'"></i>
              <i class="iconfont icon-edit-user" v-else-if="item.theType =='2'" style="color:#088fff"></i>
              <i class="iconfont icon-mine" v-else-if="item.theType =='3'" style="color:#088fff"></i>
              <i v-else class="tree-icon primary"></i>
              {{item.label}}
            </el-checkbox>

          </el-checkbox-group>
        </div>
      </el-scrollbar>
      <div class="el-dialog__footer right">
        <el-button
          size="mini"
          @click.stop="handlRefreshTheTree"
        >刷新</el-button>
        <el-button
          type="primary"
          size="mini"
          @click.stop="handleClose"
        >确定</el-button>
      </div>
    </div>
  </div>
</template>

<script>
// 多选树,由文本框和树结构选择面板组成,选中后生成标签

// 导入接口
import { unitListApi } from '@/service/api/actions' // 人员/机构目录
import { searchUnitListApi,searchUnitParentsApi } from '@/service/api/actions' // 人员/机构查询、获取所有父节点

export default {
  name: 'inputtree',
  props: {
    theTitle: { type: String, required: false },
    theEdit: { type: Boolean, default: false }, // 文本框数据是否可以键盘输入
    theRefresh: { type: String, required: false }
  },

  data () {
    return {
      checkList:[],//选中组织和人员
      oldcheckList:[],//选中组织和人员
      searchUnitlist:[],
      filterText:'',//节点过滤字段
      selectedLabel: '',
      iconClass: 'down',
      softFocus: false,
      popperDisplay: 'none',
      popperWidth: '100%',
      theSelected: { all: [], current: {} },
      theTreeConfig: {
        defaultProps: {
          value: 'theId',
          label: 'label',
          children: 'children',
          isLeaf:(data,node) =>{
            if(data.theType == 2){ // 根据需要进行条件判断添加is-leaf类名
              return  true
            }else{
              return false
            }
          }
        },
        defaultExpandedKeys: []
      }
    }
  },

  mounted () {
    document.addEventListener(
      'mouseup',
      (event) => {
        var sp = document.getElementById('input-tree')
        if (sp) {
          if (!sp.contains(event.target)) {
            this.handleClose()
          }
        }
      },
      false
    )
  },

  methods: {
    // 查询机构、人员选中后
    async handleCheckAllChange(val){
      // console.log(val)
      // let theIds = []
      let newCheckList = val
      //得到新增ID
      let differenceId = newCheckList.concat(this.oldcheckList)
        .filter(v => !newCheckList.includes(v) || !this.oldcheckList.includes(v))
      // 新增选中数据
      if(this.oldcheckList.length < newCheckList.length){
        // 得到新增数据
        let addObj = this.searchUnitlist.filter(item=>{
          return item.theId == differenceId
        })
        // debugger
        this.theSelected.all.push(addObj[0])
        // 得到选中树节点的所有父节点,加载出数据,避免选中后懒加载未加载出数据bug

        await searchUnitParentsApi(JSON.stringify(this.theSelected.all) , (res) => {
          if (res.data.code === 200) {
            this.theTreeConfig.defaultExpandedKeys = []
             res.data.data.forEach(item=>{
              item.forEach( el=>{
                if(this.theTreeConfig.defaultExpandedKeys.indexOf(el)){// 避免重复
                   this.theTreeConfig.defaultExpandedKeys.push(el.theId)
                }
              })
            })
            this.$refs.combotree.setCheckedNodes(this.theSelected.all)
            this.oldcheckList = val
          }
        })
        
      }else{
        let deleteObj
        this.theSelected.all.forEach((item,index)=>{
          if(item.theId == differenceId){
            deleteObj = index
          }
        })
        // 删除改变的数据
        this.theSelected.all.splice(deleteObj, 1)
        this.$refs.combotree.setCheckedNodes(this.theSelected.all)
      }
    },
    //树形节点过滤
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    // 文本框内图标点击事件
    handleIconClick () {
      if (!this.theEdit) {
        if (this.softFocus) {
        // 1、切换图标
          this.iconClass = 'down'
          // 2、显示树结构内容面板
          this.popperDisplay = 'none'
          this.softFocus = false
        } else {
          this.iconClass = 'right'
          this.popperDisplay = 'block'
          this.softFocus = true
        }
      }
    },

    // 选中后关闭,设置失去焦点事件
    handleClose (event) {
      // 1、切换图标
      this.iconClass = 'down'
      // 2、显示树结构内容面板
      this.popperDisplay = 'none'
      this.softFocus = false
    },

    // 目录树数据初始化方法
    loadTheTree (node, resolve) {
      if (node.level === 0) {
        let params = {
          uniId: -1
        }
        unitListApi(params, (res) => {
          if (res.data.code === 200) {
            return resolve(res.data.data)
          }
        })
      } else {
        let params = {
          uniId: node.data.theId
        }

        unitListApi(params, (res) => {
          if (res.data.code === 200) {
            return resolve(res.data.data)
          }
        })
      }
    },

    // 刷新树的根目录
    handlRefreshTheTree () {
      let _root = this.$refs.combotree.root
      if (_root !== undefined) {
        _root.childNodes.length = 0
        this.loadTheTree(_root, (data) => {
          this.$refs.combotree.root.doCreateChildren(data)
        })
      }
    },

    // 获得全路径
    handleTheTreeFullPath: function (node) {
      if (node.data !== undefined) {
        this.theSelected.all.push(node.data)
      }
      if (
        node.parent !== null &&
        node.parent !== undefined &&
        node.parent.data !== undefined
      ) {
        this.handleTheTreeFullPath(node.parent)
      }
    },
    // 选中节点数据发生改变
    handleCheckChange(data, checked, indeterminate) {
      this.theSelected.all = this.$refs.combotree.getCheckedNodes()
      this.checkList = this.$refs.combotree.getCheckedKeys()
      this.oldcheckList = this.checkList
      // 传递当前选中节点给父级
      this.$emit('handleTreeSelected', this.theSelected)
    },

    // 标签删除事件
    deleteTag (event, album) {
      if (!this.theEdit) {
        
        let index = this.theSelected.all.indexOf(album)
        if (index > -1) {
         this.theSelected.all.splice(index, 1)
         this.$refs.combotree.setCheckedNodes(this.theSelected.all)
         this.checkList = this.$refs.combotree.getCheckedKeys()
         this.oldcheckList = this.checkList
        }
        this.$emit('handleTreeSelected', this.theSelected)
      }
    }
  },

  watch: {
    checkList(val){
      // console.log(val)
// debugger
    },

    theRefresh () {
      this.theSelected.all = []
      this.theSelected.current = {}
    },
    //输入框数据发生改变,过滤节点
    filterText(val) {
      if(val){
        let params={
          name:val
        }
        searchUnitListApi(params, (res) => {
        if (res.data.code === 200) {
          this.searchUnitlist =res.data.data
        }
      })

      }
    }

  }
}
</script>

<style lang="scss" scoped>
.el-tag{
  margin: 3px 5px;
}

/deep/ .el-dialog__header {
    padding: 10px 20px 10px;
    .el-input__inner{
      font-size: 14PX;
      height: 35PX;
      line-height: 35PX;
    }
}
/deep/ .el-dialog__footer {
    padding: 10px 20px 10px;
}
.el-input__inner{
  cursor: pointer;
}

.el-checkbox-group{
  padding-left: 30px;
  .el-checkbox{
    height: 28PX;
    display: block;
  }
}
</style>

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值