element 树状下拉框

<!--

    /**

    * 树形下拉选择组件,下拉框展示树形结构,提供选择某节点功能,方便其他模块调用

    * @author sxy https://bysjb.cn

    * @date 2020-12-02

    */

-->

<template>

  <div>

    <div v-show="isShowSelect" class="mask" @click="isShowSelect = !isShowSelect" />

    <el-popover

      v-model="isShowSelect"

      placement="bottom-start"

      :width="width"

      trigger="manual"

      style="padding: 12px 0;"

      @hide="popoverHide"

    >

      <el-tree

        ref="tree"

        class="common-tree"

        :style="style"

        :data="data"

        :props="defaultProps"

        :show-checkbox="multiple"

        :node-key="nodeKey"

        :check-strictly="checkStrictly"

        default-expand-all

        :expand-on-click-node="false"

        :check-on-click-node="multiple"

        :highlight-current="true"

        @node-click="handleNodeClick"

        @check-change="handleCheckChange"

      />

      <el-select

        slot="reference"

        ref="select"

        v-model="selectedData"

        :style="selectStyle"

        :size="size"

        :multiple="multiple"

        :clearable="clearable"

        :collapse-tags="collapseTags"

        class="tree-select"

        @click.native="isShowSelect = !isShowSelect"

        @remove-tag="removeSelectedNodes"

        @clear="removeSelectedNode"

        @change="changeSelectedNodes"

      >

        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />

      </el-select>

    </el-popover>

  </div>

</template>

<script>

export default {

  props: {

    // 树结构数据

    data: {

      type: Array,

      default() {

        return []

      }

    },

    defaultProps: {

      type: Object,

      default() {

        return {

          children: 'children',

          label: 'name'

        }

      }

    },

    // 配置是否可多选

    multiple: {

      type: Boolean,

      default() {

        return false

      }

    },

    // 配置是否可清空选择

    clearable: {

      type: Boolean,

      default() {

        return false

      }

    },

    // 配置多选时是否将选中值按文字的形式展示

    collapseTags: {

      type: Boolean,

      default() {

        return false

      }

    },

    nodeKey: {

      type: String,

      default() {

        return 'id'

      }

    },

    // 显示复选框情况下,是否严格遵循父子不互相关联

    checkStrictly: {

      type: Boolean,

      default() {

        return false

      }

    },

    // 默认选中的节点key数组

    checkedKeys: {

      type: Array,

      default() {

        return []

      }

    },

    size: {

      type: String,

      default() {

        return 'medium'

      }

    },

    width: {

      type: Number,

      default() {

        return 250

      }

    },

    height: {

      type: Number,

      default() {

        return 300

      }

    }

  },

  data() {

    return {

      isShowSelect: false, // 是否显示树状选择器

      options: [],

      selectedData: [], // 选中的节点

      style: 'width:' + (this.width - 24) + 'px;' + 'height:' + this.height + 'px;',

      selectStyle: 'width:' + (this.width + 24) + 'px;',

      checkedIds: [],

      checkedData: []

    }

  },

  watch: {

    isShowSelect(val) {

      // 隐藏select自带的下拉框

      this.$refs.select.blur()

    },

    checkedKeys(val) {

      console.log('checkedKeys', val)

      if (!val) return

      this.checkedKeys = val

      this.initCheckedData()

    }

  },

  mounted() {

    this.initCheckedData()

  },

  methods: {

    // 单选时点击tree节点,设置select选项

    setSelectOption(node) {

      const tmpMap = {}

      tmpMap.value = node.key

      tmpMap.label = node.label

      this.options = []

      this.options.push(tmpMap)

      this.selectedData = node.key

    },

    // 单选,选中传进来的节点

    checkSelectedNode(checkedKeys) {

      var item = checkedKeys[0]

      this.$refs.tree.setCurrentKey(item)

      var node = this.$refs.tree.getNode(item)

      this.setSelectOption(node)

    },

    // 多选,勾选上传进来的节点

    checkSelectedNodes(checkedKeys) {

      // this.$refs.tree.setCheckedKeys(checkedKeys)

      // 优化select回显显示 有个延迟的效果

      const that = this

      setTimeout(function() {

        that.$refs.tree.setCheckedKeys(checkedKeys)

      }, 10)

      // console.log('checkSelectedNodes', checkedKeys, this.selectedData)

    },

    // 单选,清空选中

    clearSelectedNode() {

      this.selectedData = []

      this.$refs.tree.setCurrentKey(null)

    },

    // 多选,清空所有勾选

    clearSelectedNodes() {

      var checkedKeys = this.$refs.tree.getCheckedKeys() // 所有被选中的节点的 key 所组成的数组数据

      for (let i = 0; i < checkedKeys.length; i++) {

        this.$refs.tree.setChecked(checkedKeys[i], false)

      }

    },

    initCheckedData() {

      if (this.multiple) {

        // 多选

        // console.log(this.checkedKeys.length)

        if (this.checkedKeys.length > 0) {

          this.checkSelectedNodes(this.checkedKeys)

        } else {

          this.clearSelectedNodes()

        }

      } else {

        // 单选

        if (this.checkedKeys.length > 0) {

          this.checkSelectedNode(this.checkedKeys)

        } else {

          this.clearSelectedNode()

        }

      }

    },

    popoverHide() {

      if (this.multiple) {

        this.checkedIds = this.$refs.tree.getCheckedKeys() // 所有被选中的节点的 key 所组成的数组数据

        this.checkedData = this.$refs.tree.getCheckedNodes() // 所有被选中的节点所组成的数组数据

      } else {

        this.checkedIds = this.$refs.tree.getCurrentKey()

        this.checkedData = this.$refs.tree.getCurrentNode()

      }

      this.$emit('popoverHide', this.checkedIds, this.checkedData)

    },

    // 单选,节点被点击时的回调,返回被点击的节点数据

    handleNodeClick(data, node) {

      if (!this.multiple) {

        this.setSelectOption(node)

        this.isShowSelect = !this.isShowSelect

        this.$emit('change', this.selectedData)

      }

    },

    // 多选,节点勾选状态发生变化时的回调

    handleCheckChange() {

      var checkedKeys = this.$refs.tree.getCheckedKeys() // 所有被选中的节点的 key 所组成的数组数据

      // console.log('handleCheckChange', checkedKeys)

      this.options = checkedKeys.map((item) => {

        var node = this.$refs.tree.getNode(item) // 所有被选中的节点对应的node

        const tmpMap = {}

        tmpMap.value = node.key

        tmpMap.label = node.label

        return tmpMap

      })

      this.selectedData = this.options.map((item) => {

        return item.value

      })

      this.$emit('change', this.selectedData)

    },

    // 多选,删除任一select选项的回调

    removeSelectedNodes(val) {

      this.$refs.tree.setChecked(val, false)

      var node = this.$refs.tree.getNode(val)

      if (!this.checkStrictly && node.childNodes.length > 0) {

        this.treeToList(node).map(item => {

          if (item.childNodes.length <= 0) {

            this.$refs.tree.setChecked(item, false)

          }

        })

        this.handleCheckChange()

      }

      this.$emit('change', this.selectedData)

    },

    treeToList(tree) {

      var queen = []

      var out = []

      queen = queen.concat(tree)

      while (queen.length) {

        var first = queen.shift()

        if (first.childNodes) {

          queen = queen.concat(first.childNodes)

        }

        out.push(first)

      }

      return out

    },

    // 单选,清空select输入框的回调

    removeSelectedNode() {

      this.clearSelectedNode()

      this.$emit('change', this.selectedData)

    },

    // 选中的select选项改变的回调

    changeSelectedNodes(selectedData) {

      // 多选,清空select输入框时,清除树勾选

      if (this.multiple && selectedData.length <= 0) {

        this.clearSelectedNodes()

      }

      this.$emit('change', this.selectedData)

    }

  }

}

</script>

<style scoped>

  .mask {

    width: 100%;

    height: 100%;

    position: fixed;

    top: 0;

    left: 0;

    opacity: 0;

    z-index: 11;

  }

  .common-tree {

    overflow: auto;

  }

  .tree-select {

    z-index: 111;

  }

</style>

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容