TS使用el-tree拖拽结构+点击写法

1.结构分两块

<template>
  <div style="height:96%;width:100%;max-width:1920px;max-height:1080px;background-color:white;padding:20px;display: flex;flex-direction:row; ">

    <!-- 左侧树 -->
    <div style="height:100%;width:32%;">
    </div>

    <!-- 右侧两个表 -->
    <div style="height:100%;width:68%;" v-show="showTable">
    </div>

    </div>
  </div>

</template>

2.左侧树写法(主要)

  <!-- 左侧树 -->
    <div style="height:100%;width:32%;">
      <el-row style="height:30px">
        <svg-icon icon-class="organizationIcon" />
        <span class="ttac_model_title">{{$t('i18n.organization')}}</span>
      </el-row>

      <el-row style="overflow: hidden; width: 100%; bottom: 0px;height: calc(100% - 30px); ">
        <div style="overflow: auto; width: 100%; height: 100%;" @contextmenu.prevent="onTreeRightClick">
 <!-- 
            node-key	每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
            node-click	节点被点击时的回调
            node-contextmenu	当某一节点被鼠标右键点击时会触发该事件
            data	展示数据
            default-expand-all	是否默认展开所有节点
            node-drag-start	节点开始拖拽时触发的事件
            node-drag-enter	拖拽进入其他节点时触发的事件
            node-drag-leave	拖拽离开某个节点时触发的事件
            node-drag-over	在拖拽节点时触发的事件(类似浏览器的 mouseover 事件)
            node-drag-end	拖拽结束时(可能未成功)触发的事件
            node-drop	拖拽成功完成时触发的事件
            allow-drop	拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
            allow-drag	判断节点能否被拖拽
            expand-on-click-node	是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
            draggable	是否开启拖拽节点功能
            highlight-current	是否高亮当前选中节点,默认值是 false。
           -->
         <el-tree
            node-key="id"
            @node-click="showOrganizationInfo"
            @node-contextmenu="onTreeNodeRightClick"
            :data="treeData"
            default-expand-all
            @node-drag-start="handleDragStart"
            @node-drag-enter="handleDragEnter"
            @node-drag-leave="handleDragLeave"
            @node-drag-over="handleDragOver"
            @node-drag-end="handleDragEnd"
            @node-drop="handleDrop"
            :allow-drop="allowDrop"
            :allow-drag="allowDrag"
            :expand-on-click-node="false"
            draggable
            highlight-current
          >
           

            <div slot-scope="{node,data}">
              <div v-if="data.type==='people'">
                <btreeNode :value="data.label" style="margin-left: 3px; z-index: 1;" :nodeKey="data.id" :isUser="data.userId? true:false">
                  <template #icon>
                    <svg-icon icon-class="user1" />
                  </template>
                </btreeNode>
              </div>
              <div v-if="data.type==='group'">
                <btreeNode :value="data.label" style="margin-left: 3px; z-index: 1;" :nodeKey="data.id" :isUser="data.userId? true:false"
                  @onValueChanged="(id,title)=>onNodeNameChanged(id,title,data)" @onSureNodeName="(id,title)=>onSureNodeName(id,title,data)">
                  <template #icon>
                    <svg-icon icon-class="department" />
                  </template>
                </btreeNode>
              </div>
            </div>
          </el-tree>
          <chooseUserDialog ref="chooseUserDialog" @onSure="onSelectPeople" />
          <VueContextMenu id="context-menu" ref="ctxMenu" style="cursor: pointer">
            <li v-for="(menu, index) in rightMenus" :key="index" class="ttactheme_hover" style="padding-left: 5px" @click="onRightMenuChoose(menu)">
              <svg-icon :icon-class="getMenuIconByRightMenus(menu)" />
              <span style="margin-left: 3px">&nbsp;&nbsp;{{ menu }}</span>
            </li>
          </VueContextMenu>
        </div>
      </el-row>
    </div>

 data数据 :

//获取tree的数据
private async initData() {
    //所有数据
    let res = await GetAllOranizationInfo()
    //处理成树形
    this.treeData = this.organData(res, null)
  }

处理tree的数据结构,展示树形

private organData(allData: any[], topparentId: string): TreeNodeDC[] {
    let res: TreeNodeDC[] = []
    // 通过使用filter方法,从res数据中筛选出 用户的parentId  等于 大组织id的数据 , 并将结果保存在filters数组中。
    //第一次传入的是null,匹配第一个大的组织
    let filters = allData.filter((o) => o.parentId === topparentId)
    console.log('filter之后的res,', filters)
    //对匹配上的数据进行循环操作
    for (let index = 0; index < filters.length; index++) {
      //把值放到node里形成新的对象
      const element = filters[index]
      //默认组织,因为第一个开头传的null,第一次匹配到的就是最大的组织
      let node: TreeNodeDC = {
        id: element.id,
        userId: element.userId,
        label: element.name,
        parentGroupId: element.parentId,
        index: element.index,
        children: [],
        type: 'group'
      }
      //type==0是组织(group),type==1是用户(people)
      if (element.type === 1) {
        node.type = 'people'
      }
      //递归,调用自身方法,传入 第1(n)次获取到的数据的id,然后走流程
      let nodeChildren = this.organData(allData, node.id)
      console.log('nodeChildren,', nodeChildren, allData, node.id)
      // 通过使用filter方法,从res数据中筛选出 小用户的parentId  等于 大组织id的数据 , 并将结果保存在filters数组中
      //这次的就是子级,用户+组织的形式
      //对匹配上的数据进行循环操作
      //排序
      node.children = nodeChildren.sort(function(a, b) {
        return a.index - b.index
      })
      //返回node数组
      res.push(node)
    }

    return res
  }

2.1点击用户 /  组织

noadeList数据:

 // 点击node触发的方法
  private showOrganizationInfo(nodeList) {
    let idList = []
    // 如果点击的node没有子节点,但是有用户id,说明是用户
    if (nodeList.children.length == 0 && nodeList.userId != null) {
      //点击的id放到idList
      idList = [nodeList.userId]
    } else {
      // 否则点击的是组织
      idList = this.getChildIds(nodeList.children)
    }
    //如果没有点到数据
    if (idList.length == 0) {
      this.showTable = false
      this.userIds = []
    } else {
      //打开table显示
      this.showTable = true
      //没什么作用,赋值方便后续
      this.userIds = idList
    }
  }


//点击组织的处理方法
  //递归当前节点下及其子节点的数据,获取单个组织下包括所有id的集合,返回出来
  private getChildIds(nodeChildList) {
    let userIds = []
    let childUserIds = []
    nodeChildList.forEach((item) => {
      userIds.push(item.userId)
      if (item.children.length > 0) {
        childUserIds = this.getChildIds(item.children) as any
      }
    })
    return [...userIds, ...childUserIds].filter((v) => v)
  }
//节点   拖拽开始 / 进入其他节点 / 拖拽离开 / 在拖拽节点时触发的事件(类似浏览器的 mouseover 事件) / 拖拽结束时(可能未成功)触发的事件
// ***************树********************************************
  private handleDragStart(node, ev) {
    // console.log('drag start', node)
  }
  private handleDragEnter(draggingNode, dropNode, ev) {
    // console.log('tree drag enter: ', dropNode.label)
  }
  private handleDragLeave(draggingNode, dropNode, ev) {
    // console.log('tree drag leave: ', dropNode.label)
  }
  private handleDragOver(draggingNode, dropNode, ev) {
    // console.log('tree drag over: ', dropNode.label)
  }
  private handleDragEnd(draggingNode, dropNode, dropType, ev) {
    // console.log('tree drag end: ', dropNode && dropNode.label, dropType)
  }

3.右击tree的节点发生的事件,阻止冒泡和默认事件,然后启用vue-contextMenu的方法

          <VueContextMenu id="context-menu" ref="ctxMenu" style="cursor: pointer">
            //rightMenus是根据右键点击的是 组织 还是 用户 来控制显示的是什么
            //图标根据rightMenus的数据来决定,switch方法匹配
            <li v-for="(menu, index) in rightMenus" :key="index" class="ttactheme_hover" style="padding-left: 5px" @click="onRightMenuChoose(menu)">
           
              <svg-icon :icon-class="getMenuIconByRightMenus(menu)" />
              <span style="margin-left: 3px">&nbsp;&nbsp;{{ menu }}</span>
            </li>
          </VueContextMenu>
//枚举 i18里的数据
enum rightMenus {
  addPeople = 'i18n.rightMenu_addPeople',
  addGroup = 'i18n.rightMenu_addCombination',
  saveAs = 'i18n.rightMenu_saveAs',
  rename = 'i18n.rightMenu_rename',
  edit = 'i18n.rightMenu_edit',
  delete = 'i18n.rightMenu_delete'
}

 右键打开面板 展示哪些数据 的方法:

//右击菜单树,就是右击空白地方
 private onTreeRightClick(e: any) {
    //window.console.log('右击菜单树', e)
    e.stopPropagation()
    e.preventDefault()
    this.currentRightClickNode = null
    this.rightMenus = []
    this.rightMenus = [this.$t(rightMenus.addGroup).toString()]
    ;(this.$refs.ctxMenu as any).open()
  }




//右击菜单树节点
//el-tree上有个@node-contextmenu="onTreeNodeRightClick"
 private onTreeNodeRightClick(e: any, data: any) {
    // window.console.log('右击菜单树节点的节点数据', data)
    //禁止事件冒泡
    e.stopPropagation()
    //阻止默认事件执行
    e.preventDefault()
    //节点数据
    this.currentRightClickNode = data
    //清空数组
    this.rightMenus = []
    //如果点的用户
    if (data.type === 'people') {
      //只让 枚举数组里 放删除
      this.rightMenus = [this.$t(rightMenus.delete).toString()]
    } else if (data.type === 'group') {
      //添加部门的文字
      this.rightMenus = [this.$t(rightMenus.addGroup).toString(), 
      //添加人员的文字
      this.$t(rightMenus.addPeople).toString(), 
      //添加删除的文字
      this.$t(rightMenus.delete).toString()]
    }
    //通过$refs使用open方法打开框子
    ;(this.$refs.ctxMenu as any).open()
  }


//展示图标的方法
  private getMenuIconByRightMenus(rm: rightMenus): string {
    let iconString
    switch (rm) {
      case this.$t(rightMenus.addPeople).toString():
        iconString = 'rightmenu_add'
        break
      case this.$t(rightMenus.addGroup).toString(): {
        iconString = 'rightmenu_add'
        break
      }
      case this.$t(rightMenus.edit).toString():
        iconString = '&#xe628;'
        break
      case this.$t(rightMenus.saveAs).toString(): {
        iconString = '&#xe61a;'
        break
      }
      case this.$t(rightMenus.rename).toString(): {
        iconString = '&#xe628;'
        break
      }
      case this.$t(rightMenus.delete).toString(): {
        iconString = 'rightmenu_delete'
        break
      }
      default:
        break
    }
    return iconString
  }


//点击menu的数据,进行增删改查的操作
 private async onRightMenuChoose(menuName: string) {
    //window.console.log('onRightMenuChoose:', menuName)
    switch (menuName) {
      case this.$t(rightMenus.addPeople).toString():
        this.addPeople()
        break
      case this.$t(rightMenus.addGroup).toString():
        this.addGroup()
        break
      case this.$t(rightMenus.delete).toString():
        this.deleteNode()
        this.onDeletePage(this.currentRightClickNode.id)
        break
      case this.$t(rightMenus.edit).toString():
        this.onEditPage(this.currentRightClickNode.id)
        break
      default:
        break
    }
  }

4.拖拽成功时触发的事件,基本就是调用接口了

  private async handleDrop(draggingNode, dropNode, dropType, ev) {
    // ****************************************
    let parentGroupId = null
    if (dropType === 'inner') {
      parentGroupId = dropNode.data.id
    } else if (dropType === 'before') {
      parentGroupId = dropNode.data.parentGroupId
    } else if (dropType === 'after') {
      parentGroupId = dropNode.data.parentGroupId
    }
    let dragingNodeData = this.searchNodeById(draggingNode.data.id, this.treeData)
    dragingNodeData.parentGroupId = parentGroupId
    if (dragingNodeData.type === 'people') {
      let data = this.makeDesignPageDCByNode(dragingNodeData)
      await AddOrUpdateOranizationInfo(data)
    } else if (dragingNodeData.type === 'group') {
      let data = this.makeDesignPageGroupDCByNode(dragingNodeData)
      await AddOrUpdateOranizationInfo(data)
    }
    // ****************************************
    let needOrderNodes = []
    if (parentGroupId) {
      let parentNodeData = this.searchNodeById(parentGroupId, this.treeData)
      needOrderNodes = parentNodeData.children
    } else {
      needOrderNodes = this.treeData
    }
    for (let index = 0; index < needOrderNodes.length; index++) {
      needOrderNodes[index].index = index
    }

    let updateIndexData: any[] = []
    for (let index = 0; index < needOrderNodes.length; index++) {
      const element = needOrderNodes[index]
      updateIndexData.push({
        oranizationId: element.id,
        index: element.index
      })
    }

    window.console.log('needOrderNodes:', updateIndexData)
    await UpdateOranizationSort(needOrderNodes)
  }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值