欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue实现多栏布局拖拽

程序员文章站 2022-08-10 15:09:09
本文实例为大家分享了vue实现多栏布局拖拽的具体代码,供大家参考,具体内容如下一、目标vue 实现多个盒子(用户根据实际场景决定盒子数量)*拖拽,改变宽度。二、应用场景可*拖动宽度的多栏布局。最典...

本文实例为大家分享了vue实现多栏布局拖拽的具体代码,供大家参考,具体内容如下

一、目标

vue 实现多个盒子(用户根据实际场景决定盒子数量)*拖拽,改变宽度。

二、应用场景

可*拖动宽度的多栏布局。

最典型的案例:编辑器(eg:vscode,idea等)

vue实现多栏布局拖拽

三、组件设计

由于该组件盒子数量不确定,所以我们设计组件时参考了vuetify中的form和formitem的设计。即:外层大盒子处理分发的拖拽事件,里层的盒子负责展示各个item的内容。

组件设计实现目标:

<drag-box style="width: 100%; height: 100%;">
   <drag-item>item1</drag-item>
   <drag-item>item2</drag-item>
   <drag-item>item3</drag-item>
   <drag-item>item4</drag-item>
</drag-box>

四、实现

4.1 dragbox 静态页面

(通过插槽实现子元素的嵌套)

<template>
    <div ref='dragbox' style='display: flex; width: 100%; height: 100%;'>
        <slot></slot>
    </div>
</template>

4.2 dragitem 页面

(通过插槽实现drag-item内部元素的嵌套)

<template>
    <div ref="container" class="d-flex" style="min-width: 200px; position: relative;">
        <div style="width: 100%; height: 100%;">
            <slot>默认信息</slot>
        </div>
  <!-- 拖拽条 -->
        <div v-if="resizeshow" class="resize" />
    </div>
</template>
<script>
export default {
  props: {
  // 控制拖拽条的是否显示,默认显示
    resizeshow: {
      type: boolean,
      default: true
    }
  }
}
</script>
<style>
.resize {
    position: absolute;
    top: 0;
    right: 0;
    width: 4px;
    height: 100%;
    cursor: col-resize;
    background-color: #d6d6d6;
}
</style>

4.3 拖拽逻辑

拖拽的逻辑应当交给dragbox处理,而非dragitem。

4.3.1 在实现拖拽之前,应当给子元素(即:dragitem)进行合理布局。

当用户未给 dragitem 分配初始宽度时,则默认flex:1(平均分配剩余空间)。具体逻辑如下:

 // 如果dragitem 没有定义宽度,则flex=1
    setdragitemflex () {
      const dragbox = this.$refs.dragbox
      const childslen = dragbox.children.length

      for (let i = 0; i < childslen; i++) {
        const node = dragbox.children[i]
        if (!node.style.width) {
          // 如果没有定义宽度,则flex=1
          node.style.flex = 1
        }
      }
    },

4.3.2 拖拽实现逻辑

应当为每个dragitem的拖动条添加拖动事件。完整的拖动事件包括:鼠标按下,鼠标移动,鼠标抬起(拖动结束)。

循环为每个拖动条添加事件:

dragcontrollerdiv () {
  const resize = document.getelementsbyclassname('resize') // 拖拽条
  // 循环为每个拖拽条添加事件
  for (let i = 0; i < resize.length; i++) {
    // 鼠标按下事件
    resize[i].addeventlistener('mousedown', this.onmousedown)
  }
},

鼠标按下逻辑:获取鼠标按下的初始位置,改变拖拽条颜色,添加move和up的监听事件。

onmousedown (e) {
  this.resizebox = e.target
  this.currentbox = this.resizebox.parentnode// 当前盒子
  this.rightbox = this.getnextelement(this.currentbox)// 当前盒子的下个兄弟节点
  if (!this.rightbox) return
  this.curlen = this.currentbox.clientwidth
  this.otherboxwidth = this.$refs.dragbox.clientwidth - this.currentbox.clientwidth - this.rightbox.clientwidth // 其他盒子的宽度
  // 颜色改变提醒
  this.resizebox.style.background = '#818181'
  this.startx = e.clientx
  document.addeventlistener('mousemove', this.onmousemove)
  document.addeventlistener('mouseup', this.onmouseup)
},

// 获取下一个兄弟元素的兼容函数
getnextelement (element) {
  if (element.nextelementsibling) {
    return element.nextelementsibling
  } else {
    var next = element.nextsibling// 下一个兄弟节点
    while (next && next.nodetype !== 1) { // 有 并且 不是我想要的
      next = next.nextsibling
    }
    return next
  }
}

鼠标移动事件:计算并设置当前盒子和右侧盒子的宽度。

onmousemove (e) {
  const endx = e.clientx
  const movelen = endx - this.startx // (endx-startx)= 移动的距离
  const curboxlen = this.curlen + movelen // resize[i].left+移动的距离=左边区域最后的宽度
  const rightboxlen = this.$refs.dragbox.clientwidth - curboxlen - this.otherboxwidth // 右侧宽度=总宽度-左侧宽度-其它盒子宽度
  // 当最小宽度时,无法继续拖动
  if (curboxlen <= 200 || rightboxlen <= 200) return
  this.currentbox.style.width = curboxlen + 'px'// 当前盒子的宽度
  this.resizebox.style.left = curboxlen // 设置左侧区域的宽度
  this.rightbox.style.width = rightboxlen + 'px'
},

鼠标抬起事件:销毁mousedown和mousemove事件;恢复拖拽条的颜色。

onmouseup () {
 // 颜色恢复
 this.resizebox.style.background = '#d6d6d6'
 document.removeeventlistener('mousedown', this.onmousedown)
 document.removeeventlistener('mousemove', this.onmousemove)
},

在mounted钩子函数里添加对应的事件。

mounted () {
  this.setdragitemflex()
  this.dragcontrollerdiv()
},

引入并注册使用该组件:

<template>
  <div id="app" style="width: 100%; height: 100vh; border:1px solid #ccc;">
    <drag-box style="width: 100%; height: 100%;">
      <drag-item style="width: 20%;">item1</drag-item>
      <drag-item>item2</drag-item>
      <drag-item style="width: 20%;" :resizeshow='false'>item3</drag-item>
    </drag-box>
  </div>
</template>

<script>
import {dragbox, dragitem} from './components/draglayouter'

export default {
  name: 'app',
  components: {
    dragbox,
    dragitem
  }
}
</script>

五、运行结果

vue实现多栏布局拖拽

具体样式可后期修改。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

相关标签: vue 布局 拖拽