vue+element ui 的el-tree组件实现将任意节点拖动到对应的div中

1,260 阅读1分钟

1.HTML页面渲染

构建三个面板,面板1渲染需要被拖动的节点树,面板2和面板3用于接收并展示被拖动到该区域的节点,且面板1和面板2必须是固定的高度(自适应的目前不适用,无法获取固定的 x,y 范围)。

代码如下:

<template>
  <div class="app-container">
  	<!-- 面板1 -->
    <div class="div1 normalDivStyle">
      <!-- 数据库表及其字段 -->
      <div class="fieldMenu normalMenuStyle">
        <div class="title">面板1</div>
        <el-tree
          ref="tableTree"
          :data="tableList"
          show-checkbox
          node-key="id"
          :props="defaultProps"
          draggable
          :allow-drop="returnFalse"
          @node-drag-end="handleDragend"
        />
      </div>
    </div>

    <div class="div2 normalDivStyle">
      <!-- 面板2 -->
      <div class="xyMenu normalMenuStyle" style="height:100px">
        <div class="title">面板2</div>
        <div class="content">
          <p>{{ xNodeArr.label }}</p>
        </div>
      </div>
      
      <!-- 面板3 -->
      <div class="xyMenu normalMenuStyle">
        <div class="title">面板3</div>
        <div class="content">
          <p>{{ yNodeArr.label }}</p>
        </div>
      </div>
    </div>

  </div>
</template>

其中 draggable 表示是否开启节点拖拽功能,allow-drop 拖拽时判定目标节点能否被放置,node-drag-end 拖拽结束时(可能未成功)触发的事件,具体参考官方

2.定义所需的变量

      defaultProps: {
        children: 'children',
        label: 'label'
      },
      // 树形控件渲染数据
      tableList: [{
        id: 1,
        label: '一级 1',
        children: [{
          id: 4,
          label: '二级 1-1'
        }]
      }, {
        id: 2,
        label: '一级 2',
        children: [{
          id: 5,
          label: '二级 2-1'
        }, {
          id: 6,
          label: '二级 2-2'
        }]
      }, {
        id: 3,
        label: '一级 3',
        children: [{
          id: 7,
          label: '二级 3-1'
        }, {
          id: 8,
          label: '二级 3-2'
        }]
      }],
      
      xNodeArr: {},//面板2接收
      yNodeArr: {},//面板3接收

3.方法实现

主要获取面板1与面板2在浏览器中的 x 与 y 的位置范围,再根据拖拽结束时鼠标所在 x,y 位置来判断将节点放入哪个面板中。

    // 拖拽结束时(可能未成功)触发的事件
    handleDragend(draggingNode, endNode, position, event) {
      // debugger
      if (draggingNode.level === 2) {// 只拖拽第2级节点
        // @mousemove='updateXY'//获取鼠标点击时的位置
        // 根据拖拽结束时鼠标的坐标位置来判断将变量放入哪个面板中
        if (event.x > 332 && event.x < 581 && event.y > 167 && event.y < 231) {// 面板1所在浏览器中x,y的区间范围
          this.xNodeArr = {
            tableName: draggingNode.parent.data.label,
            label: draggingNode.data.label,
            columnIndex: 'baseColumn'
          }
        } else if (event.x > 332 && event.x < 581 && event.y > 285 && event.y < 451) {// 面板2所在浏览器中x,y的区间范围
          this.yNodeArr = {
            tableName: draggingNode.parent.data.label,
            label: draggingNode.data.label,
            columnIndex: 'baseColumn'
          }
        } else {
          this.$message({
            type: 'warning',
            message: '请将变量拖入对应的框中!'
          })
        }
      }
    },
    
    returnFalse() {
      return false
    },

4.样式

<style lang="scss">
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
.normalDivStyle{
  float: left;
  background-color: #fff;
  padding: 15px;
  box-shadow: 0 1px 1px rgb(0 0 0 / 10%);
  border-top: 3px solid #d2d6de;
}

.normalMenuStyle{
  border: 1px solid #EBEEF5;
  border-radius: 4px;
  overflow: auto;
  display: inline-block;
  vertical-align: middle;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  position: relative;
}
.title{
  width:100%;
  height:35px;
  line-height:15px;
  padding:10px;
  background-color:#F5F7FA;
  border-bottom: 1px solid #e4e4e5;
  color:#409EFF;
  font-size:14px;
  // text-align: center;
  font-weight: 700;
}
.content{
  width:100%;
  height: auto;
  padding: 10px;
  p{
    margin: 0 0 10px 0;
    font-size: 14px;
    color: #606266;
  }
}

.div1{
  width: 14.5%;
  position: absolute;
  left: 20px;
  top: 53px;
  bottom: 25px;
  overflow: hidden;
  .fieldMenu{
    width:100%;
    height: 40%;
  }
}
.div2{
  width: 14.5%;
  position: absolute;
  left: 16.5%;
  top: 53px;
  bottom: 25px;
  .xyMenu{
    width:100%;
    height: 200px;
    margin-bottom: 20px;
  }
}
</style>

5.效果展示