vue2 ztree 单选框

项目使用antd,下拉框太难用了,封装一个,其他ui框架改模板就行就用了一个ant的input

<template>
  <div class="tree_select_content">
    <a-input v-model="showValue" placeholder="请选择" @input="handleInput" />
    <div class="pop" :style="{display:(showPop?'block':'none')}">
      <ul id="treeSelect" class="ztree"></ul>
    </div>
  </div>
</template>

本来想格式化任何树的数据来着,发现后端给的格式不太支持,format方法可以直接弃用(keyoption是配合格式化数据的),nodes格式按注释来或者不嵌套children的使用pid那种单数组的应该也行,搜索那块的逻辑得改 

展示、搜索、选中这三个变量感觉没必要,,没咋优化也,有可能有用呢,,

<script>
export default {
  props: {
    /** ztree 原始数据 固定格式 */
    nodes: {
      type: Array,
      default() {
        return [
          // {
          //   id: 1, pId: 0, name: '111', code: '父code1', nocheck: true, children:
          //     [
          //       { id: '1-1', pId: 1, name: '222', code: '子code1' }
          //     ]
          // },
          // {
          //   id: 2, pId: 0, name: '333', code: '父code2', nocheck: true, children:
          //     [
          //       { id: '2-1', pId: 2, name: '444', code: '子code2' },
          //       { id: '2-2', pId: 2, name: '6', code: '子code3' }
          //     ]
          // },
          // {
          //   id: 3, pId: 0, name: '666', code: '父code3', nocheck: true, children:
          //     [
          //       { id: '3-1', pId: 3, name: '777', code: '子code4' },
          //       { id: '3-2', pId: 3, name: '888', code: '子code5' },
          //       { id: '3-3', pId: 3, name: '889', code: '子code5' },
          //       { id: '3-4', pId: 3, name: '880', code: '子code5' },
          //       { id: '3-5', pId: 3, name: '881', code: '子code5' },
          //       { id: '3-6', pId: 3, name: '882', code: '子code5' },
          //       { id: '3-7', pId: 3, name: '883', code: '子code5' },
          //       { id: '3-8', pId: 3, name: '884', code: '子code5' },
          //       { id: '3-9', pId: 3, name: '885', code: '子code5' },
          //       { id: '3-20', pId: 3, name: '886', code: '子code5' }
          //     ]
          // },
          // {
          //   id: '3-122', pId: 0, name: '777', code: 'code4'
          // }
        ]
      }
    },
    keyOption: {
      type: Object,
      default() {
        return {
          // fatherKey: 'id', // 父 唯一标识的 key
          // fatherCode: 'id', // 父 code
          // fatherLabel: 'name', // 父 lable
          // childKey: 'member', // 子所在obj的 key
          // childrenKey: 'personCode', // 子 唯一标识的 key
          // childrenCode: 'personCode', // 子 code
          // childrenLabel: 'personName' // 子 lable
        }
      }
    }
  },
  data() {
    return {
      /** 展示pop */
      showPop: false,
      /** 展示 */
      showValue: undefined,
      /** 选中 */
      checkedValue: undefined,
      /** 搜索 */
      searchValue: undefined,
      /** ztree设置 */
      setting: {
        data: {
          simpleData: {
            enable: true,
            idKey: 'id',
            pIdKey: 'pId',
            rootPId: 0,
          },
        },
        view: {
          showLine: false,
          showIcon: false,
          dblClickExpand: false,
          nameIsHTML: true,
          selectedMulti: false,
          showTitle: false,
        },
        check: {
          enable: true,
          chkStyle: 'radio',
          radioType: 'all'
        },
        callback: {
          onClick: (event, treeId, treeNode) => this.click(event, treeId, treeNode),
          onCheck: (event, treeId, treeNode) => this.check(event, treeId, treeNode)
        },
      },
      formatNodes: []
    }
  },
  computed: {
    myNodes() {
      if (this.searchValue) {
        return this.filterNodes(this.formatNodes)
      } else {
        return this.formatNodes
      }
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.formatNodes = this.format(this.nodes, this.keyOption)
      this.init()
      document.addEventListener('click', this.handleListenerAreaClick)
    })
  },
  beforeDestroy() {
    document.removeEventListener('click', this.handleListenerAreaClick)
  },
  methods: {
    /** 格式化原始数据 仅适用于两层结构 */
    format(arr, options) {
      const n = []
      for (let i = 0; i < arr.length; i++) {
        // 第一层
        const obj = {
          id: arr[i][options.fatherKey],
          pId: '0',
          name: arr[i][options.fatherLabel],
          code: arr[i][options.fatherCode],
          nocheck: true,
          children: []
        }
        // 第二层
        const childArr = arr[i][options.childKey]
        if (childArr && childArr.length > 0) {
          for (let j = 0; j < childArr.length; j++) {
            const childObj = {
              id: childArr[j][options.childrenKey],
              pId: arr[i][options.fatherKey],
              name: childArr[j][options.childrenLabel],
              code: childArr[j][options.childrenCode]
            }
            obj.children.push(childObj)
          }
        }
        n.push(obj)
      }
      return n
    },
    /** 初始化 */
    init() {
      $.fn.zTree.destroy('#treeSelect') // 销毁
      $.fn.zTree.init($('#treeSelect'), this.setting, this.myNodes)
      var zTree = $.fn.zTree.getZTreeObj('treeSelect')
      zTree.expandAll(true)
    },
    /** 监听区域内外点击 */
    handleListenerAreaClick(e) {
      if (!this.$el || !this.$el.compareDocumentPosition) {
        return false
      }
      const cp = this.$el.compareDocumentPosition(e.target)
      if ([16, 20].indexOf(cp) === -1 && this.$el != e.target) {
        this.showPop = false
        if (this.showValue === '') {
          this.checkedValue = undefined
        }
        this.showValue = this.checkedValue
        if (this.searchValue) {
          this.searchValue = undefined
          this.init()
        }
      } else {
        this.showPop = true
        this.showValue = this.checkedValue
      }
    },
    /** ztree节点点击事件 */
    click(e, treeId, treeNode) {
      var zTree = $.fn.zTree.getZTreeObj('treeSelect')
      if (treeNode.children && treeNode.children.length > 0) { // 选中父节点展开
        zTree.expandNode(treeNode)
      } else { // 选中子节点进行操作
        // zTree.checkNode(treeNode, false, true) // 取消勾选
        zTree.checkNode(treeNode, true, true) // 勾选
        this.showValue = treeNode.name
        this.checkedValue = treeNode.name
        this.searchValue = undefined
        setTimeout(() => {
          this.showPop = false
        }, 100)
        this.$emit('treeClick', treeNode)
      }
    },
    /** ztree单选点击事件 */
    check(e, treeId, treeNode) {
      this.showValue = treeNode.name
      this.checkedValue = treeNode.name
      this.searchValue = undefined
      setTimeout(() => {
        this.showPop = false
      }, 100)
      this.$emit('treeClick', treeNode)
    },
    /** 输入 */
    handleInput() {
      this.searchValue = this.showValue
      this.init()
    },
    /**
     * 获取搜索的node
     * node: array 
     */
    filterNodes(nodes) {
      const filterTree = []
      for (let i = 0; i < nodes.length; i++) {
        // 本层
        const has = nodes[i].name.includes(this.searchValue)
        if (has) {
          filterTree.push(nodes[i])
          continue
        }
        // 子层
        const childNodes = nodes[i].children
        if (childNodes && childNodes.length > 0) {
          filterTree.push(...this.filterNodes(childNodes))
        }
      }
      return filterTree
    }
  }
}
</script>
<style lang="less" scoped>
.tree_select_content {
  width: 100%;
  position: relative;
  display: inline-block;

  .ztree /deep/li span {
    font-family: 'Microsoft YaHei', '宋体', Arial, sans-serif;
    font-size: 12px;
  }
  .ztree /deep/li span.button.switch {
    display: none;
  }
  // .ztree /deep/li span.button.chk.radio_false_full {
  //   position: absolute;
  //   right: 0;
  // }
  // .ztree /deep/li span.button.chk.radio_false_full_focus {
  //   position: absolute;
  //   right: 0;
  // }
  // .ztree /deep/li span.button.chk.radio_true_full {
  //   position: absolute;
  //   right: 0;
  // }
  // .ztree /deep/li span.button.chk.radio_true_full_focus {
  //   position: absolute;
  //   right: 0;
  // }
  .ztree /deep/li a {
    width: 100%;
  }
  .ztree /deep/li .node_name {
    display: inline-block;
    width: 100%;
  }
  .pop {
    width: 100%;
    max-height: 200px;
    overflow-y: scroll;
    color: rgba(0, 0, 0, 0.65);
    -webkit-font-feature-settings: 'tnum';
    font-feature-settings: 'tnum';
    position: absolute;
    z-index: 1050;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    background-color: #f9f9f9;
    padding: 12px 16px 12px 6px;
    margin-top: 5px;
    border-radius: 4px;
    -webkit-box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
    box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
  }
}
</style>

菜鸡一枚,望大佬们有时间的话能指导指导

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值