基于Vue3实现鼠标按下某个元素进行拖动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能

2023-11-07

前言

其原理主要是利用JavaScript中的鼠标事件来控制CSS样式。大致就是监听某个DOM元素的鼠标按下事件,以及按下之后的移动事件和松开事件。在鼠标按下且移动过程中,可实时获得鼠标的X轴坐标的值,通过简单计算,可计算出目标元素的宽度,然后再用CSS赋值就实现该效果了。

一、示例代码

(1)/src/views/Example/MouseResizeWidth/index.vue

<template>
  <div class="index">
    <div class="index-left" ref="indexLeftRef">
      <div class="left-area-box"></div>
 
      <div class="left-resize-bar">⋮</div>
 
      <div class="left-view-more" @click="handleViewMoreLeftClick">
        <div class="left-view-more-content">
          <div class="left-view-more-false" v-if="!isCollapseLeft" />
          <div class="left-view-more-true" v-else />
        </div>
      </div>
    </div>
 
    <div class="index-middle" ref="indexRightRef">
      <div class="middle-area-box">
        <div class="middle-area-box_main">
          <div class="middle-area-box_main_up">
            <div class="middle-area-box_main_up_wrapper">
              <!-- ^ 工具栏 -->
              <div class="index-tools-container">
                <el-form :inline="true" style="display: flex">
                  <div class="tools-left"></div>
          
                  <div class="tools-right">
                    <el-form-item style="margin: 0 0 7px 7px">
                      <el-button size="small" type="primary">
                        <el-icon :size="12" style="margin-right: 5px"><ElementPlus /></el-icon>
                        <small>ElementPlus</small>
                      </el-button>
                    </el-form-item>
                  </div>
                </el-form>
              </div>
              <!-- / 工具栏 -->
 
              <!-- ^ 内容区 -->
              <div class="index-table-container">
                <el-table
                  border
                  size="small"
                  row-key="id"
                  ref="tableRef"
                  height="100%"
                  highlight-current-row
                  :data="tableList"
                >
 
                  <el-table-column fixed type="selection" :resizable="false" width="30" reserve-selection align="center" />
                  <el-table-column prop="name" label="英雄名称" align="center" width="200" show-overflow-tooltip />
                  <el-table-column prop="description" label="英雄描述" align="center" width="auto" show-overflow-tooltip />
                  <el-table-column prop="firstSkill" label="一技能" align="center" width="200" show-overflow-tooltip />
                  <el-table-column prop="secondSkill" label="二技能" align="center" width="200" show-overflow-tooltip />
                  <el-table-column prop="thirdSkill" label="三技能" align="center" width="200" show-overflow-tooltip />
 
                  <template #empty v-if="tableList == undefined || tableList.length == 0">Nothing ~</template>
                </el-table>
              </div>
              <!-- / 内容区 -->
            </div>
          </div>
        </div>
      </div>
    </div>
 
    <div class="index-right" ref="indexRightRef">
      <div class="right-view-more" @click="handleViewMoreRightClick">
        <div class="right-view-more-content">
          <div class="right-view-more-false" v-if="!isCollapseRight" />
          <div class="right-view-more-true" v-else />
        </div>
      </div>
 
      <div class="right-resize-bar">⋮</div>
 
      <div class="right-area-box"></div>
    </div>
  </div>
</template>
 
<script setup>
import { h, onMounted, onUnmounted, ref, getCurrentInstance, reactive, watch, nextTick } from 'vue'
 
// 代理对象
const { proxy } = getCurrentInstance()
 
// 是否收起左侧
const isCollapseLeft = ref(false)
// 左侧模块箭头点击事件句柄方法
const handleViewMoreLeftClick = async () => {
  const indexLeftRef = await proxy.$refs.indexLeftRef
  isCollapseLeft.value = !isCollapseLeft.value
  if (isCollapseLeft.value) {
    indexLeftRef.style.width = '23px'
  } else {
    indexLeftRef.style.width = '400px'
  }
}
 
// 表格实例
const tableRef = ref(null)
 
// 表格数据
const tableList = ref([])
 
// 是否收起右侧
const isCollapseRight = ref(false)
// 右侧模块箭头点击事件句柄方法
const handleViewMoreRightClick = async () => {
  const indexRightRef = await proxy.$refs.indexRightRef
  isCollapseRight.value = !isCollapseRight.value
  if (isCollapseRight.value) {
    indexRightRef.style.width = '23px'
  } else {
    indexRightRef.style.width = '400px'
  }
}
 
/**
 * 左侧拖动改变宽度事件句柄方法
 */
const handleDragLeftResizeBar = () => {
  var leftResizeBar = document.getElementsByClassName("left-resize-bar")[0]
  var wholeArea = document.getElementsByClassName("index")[0]
  var leftArea = document.getElementsByClassName("index-left")[0]
  var middleArea = document.getElementsByClassName("index-middle")[0]
  var rightArea = document.getElementsByClassName("index-right")[0]
  console.log('leftResizeBar =>', leftResizeBar)
  console.log('wholeArea =>', wholeArea)
  console.log('leftArea =>', leftArea)
  console.log('middleArea =>', middleArea)
  console.log('rightArea =>', rightArea)
 
  // 鼠标按下事件
  leftResizeBar.onmousedown = function (eventDown) {
    // 颜色提醒
    leftResizeBar.style.backgroundColor = "#5e7ce0"
    leftResizeBar.style.color = "#ffffff"
 
    // 鼠标拖动事件
    document.onmousemove = function (eventMove) {
      
      let width = eventMove.clientX + 20
      console.log('width =>', width)
      if (width >= 800) {
        width = 800 // 设置最大拉伸宽度为800
      } else if (width <= 23) {
        // 当拉伸宽度为小于或等于23,最小拉伸宽度为23,同时是否收起图标向右
        width = 23
        isCollapseLeft.value = true
      } else {
        // 当拉伸宽度为大于23且小于600,是否收起图标向左
        isCollapseLeft.value = false
      }
      leftArea.style.width = width + 'px'
    }
 
    // 鼠标松开事件
    document.onmouseup = function (evt) {
      // 颜色恢复
      leftResizeBar.style.backgroundColor = "#ffffff"
      leftResizeBar.style.color = "#40485c"
 
      document.onmousemove = null
      document.onmouseup = null
      leftResizeBar.releaseCapture && leftResizeBar.releaseCapture();
    }
 
    leftResizeBar.setCapture && leftResizeBar.setCapture();
    return false
  }
}
 
/**
 * 右侧拖动改变宽度事件句柄方法
 */
const handleDragRightResizeBar = () => {
  var rightResizeBar = document.getElementsByClassName("right-resize-bar")[0]
  var wholeArea = document.getElementsByClassName("index")[0]
  var leftArea = document.getElementsByClassName("index-left")[0]
  var middleArea = document.getElementsByClassName("index-middle")[0]
  var rightArea = document.getElementsByClassName("index-right")[0]
  console.log('rightResizeBar =>', rightResizeBar)
  console.log('wholeArea =>', wholeArea)
  console.log('leftArea =>', leftArea)
  console.log('middleArea =>', middleArea)
  console.log('rightArea =>', rightArea)
 
  // 鼠标按下事件
  rightResizeBar.onmousedown = function (eventDown) {
    // 颜色提醒
    rightResizeBar.style.backgroundColor = "#5e7ce0"
    rightResizeBar.style.color = "#ffffff"
 
    // 开始x坐标
    // let startX = eventDown.clientX
    // console.log('startX =>', startX)
 
    // 鼠标拖动事件
    document.onmousemove = function (eventMove) {
      // 方式一:基于移动距离方式实现
      // const endX = eventMove.clientX // 结束坐标
      // const len = startX - endX // 移动距离
      // rightArea.style.width = rightArea.clientWidth + len + 'px' // 改变宽度
      // startX = endX // 重新对开始x坐标赋值
 
      // 方式二:基于总长度和结束x坐标方式实现
      let width = wholeArea.clientWidth + 20 - eventMove.clientX
      if (width >= 800) {
        width = 800 // 设置最大拉伸宽度为800
      } else if (width <= 23) {
        // 当拉伸宽度为小于或等于23,最小拉伸宽度为23,同时是否收起图标向左
        width = 23
        isCollapseRight.value = true
      } else {
        // 当拉伸宽度为大于23且小于600,是否收起图标向右
        isCollapseRight.value = false
      }
      rightArea.style.width = width + 'px'
    }
 
    // 鼠标松开事件
    document.onmouseup = function (evt) {
      // 颜色恢复
      rightResizeBar.style.backgroundColor = "#ffffff"
      rightResizeBar.style.color = "#40485c"
 
      document.onmousemove = null
      document.onmouseup = null
      rightResizeBar.releaseCapture && rightResizeBar.releaseCapture();
    }
 
    rightResizeBar.setCapture && rightResizeBar.setCapture();
    return false
  }
}
 
onMounted(() => {
  handleDragLeftResizeBar()
  handleDragRightResizeBar()
})
 
onUnmounted(() => {
  // ...
})
</script>
 
<style lang="less" scoped>
  .index {
    display: flex;
    flex-direction: row;
    width: 100%;
    height: 100%;
    overflow: hidden;
 
    /* ---- ^ 左边 ---- */
    :deep(.index-left) {
      position: relative;
      z-index: 2;
      display: flex;
      flex-direction: row;
      width: 400px;
      border-right: 1px solid #dcdfe6;
 
      // ^ 左侧区域
      .left-area-box {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background-color: #f8f8f8;
      }
      // / 左侧区域
 
      // ^ 是否收起左侧边栏的图标
      .left-view-more {
        position: relative;
        width: 15px;
        height: 100%;
        background-color: #f3f6f8;
        border-left: 1px solid #dcdfe6;
 
        .left-view-more-content {
          width: 12px;
          height: 30px;
          background-color: #ccc;
          border-bottom-right-radius: 4px;
          border-top-right-radius: 4px;
          position: absolute;
          display: block;
          margin: auto;
          left: 0;
          top: 0;
          bottom: 0;
          cursor: pointer;
          z-index: 1;
          transition: all ease 0.3s;
 
          &:hover {
            background-color: #5e7ce0;
          }
 
          .left-view-more-true {
            width: 100%;
            height: 10px;
            position: absolute;
            display: block;
            margin: auto;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
 
            &::before {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              left: 0;
              top: 0;
              background-color: #fff;
              transform: rotate(70deg);
            }
 
            &::after {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              left: 0;
              bottom: 0;
              background-color: #fff;
              transform: rotate(-70deg);
            }
          }
 
          .left-view-more-false {
            width: 100%;
            height: 10px;
            position: absolute;
            display: block;
            margin: auto;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
 
            &::before {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              left: 0;
              top: 0;
              background-color: #fff;
              transform: rotate(-70deg);
            }
 
            &::after {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              left: 0;
              bottom: 0;
              background-color: #fff;
              transform: rotate(70deg);
            }
          }
        }
      }
      // / 是否收起左侧边栏的图标
 
      // ^ 左侧拖动条
      .left-resize-bar {
        display: flex;
        align-items: center;
        width: 7px;
        height: 100%;
        background-color: rgb(255, 255, 255);
        cursor: col-resize;
        user-select: none;
        transition: all ease 0.3s;
        font-size: 20px;
        color: #40485c;
 
        &:hover {
          color: #fff !important;
          background-color: #5e7ce0 !important;
        }
      }
      // / 左侧拖动条
    }
    /* ---- / 左边 ---- */
 
    /* ---- ^ 中间 ---- */
    :deep(.index-middle) {
      position: relative;
      z-index: 1;
      flex: 1;
      overflow: hidden;
      position: relative;
      transition: all ease 0.3s;
      background-color: #f3f6f8;
 
      // ^ 中间区域
      .middle-area-box {
        display: flex;
        position: relative;
        width: 100%;
        height: 100%;
        overflow: hidden;
 
        .middle-area-box_main {
          position: relative;
          flex: 1 1;
          display: flex;
          flex-direction: column;
          width: 100%;
 
          .middle-area-box_main_up {
            flex: 1;
            display: flex;
            overflow: hidden;
            flex-direction: column;
            background-color: #fff;
  
            .middle-area-box_main_up_wrapper {
              flex: 1;
              display: flex;
              flex-direction: column;
              padding: 7px;
              overflow: auto;
 
              .index-tools-container {
                .tools-left {
                  flex: 1;
                }
                .tools-right {
                  height: auto;
                }
              }
 
              .index-table-container {
                flex: 1;
                overflow: auto;
              }
 
              .el-table {
 
                th .cell {
                  padding: 2.5px;
                  font-weight: normal;
                  font-size: 13px;
                }
 
                td .cell {
                  padding: 2.5px 0;
                  color: #000;
                  font-size: 13px;
                }
 
                .el-table__cell {
                  padding: 0;
                }
 
                /* ^ 表格复选框 */
                .el-table-column--selection {
 
                  .cell {
                    width: 100%;
                    display: block;
 
                    .el-checkbox {
 
                      .el-checkbox__inner {
                        transform: scale(1.2);
                        border-radius: 50%;
                        border: 1px solid #bbb;
                      }
 
                      .el-checkbox__input.is-checked .el-checkbox__inner,
                      .el-checkbox__input.is-indeterminate .el-checkbox__inner {
                        border: 1px solid #5e7ce0;
                      }
                    }
                  }
                }
                /* / 表格复选框 */
              }
            }
          }

          .middle-area-box_main_down {
            flex: 0;
          }
        }
      }
      // / 中间区域
    }
    /* ---- / 中间 ---- */
 
    /* ---- ^ 右边 ---- */
    :deep(.index-right) {
      position: relative;
      z-index: 2;
      display: flex;
      flex-direction: row;
      width: 400px;
      border-left: 1px solid #dcdfe6;
 
      // ^ 是否收起右侧边栏的图标
      .right-view-more {
        position: relative;
        width: 15px;
        height: 100%;
        background-color: #f3f6f8;
        border-right: 1px solid #dcdfe6;
        
        .right-view-more-content {
          width: 12px;
          height: 30px;
          background-color: #ccc;
          border-bottom-left-radius: 4px;
          border-top-left-radius: 4px;
          position: absolute;
          display: block;
          margin: auto;
          right: 0;
          top: 0;
          bottom: 0;
          cursor: pointer;
          z-index: 1;
          transition: all ease 0.3s;
 
          &:hover {
            background-color: #5e7ce0;
          }
 
          .right-view-more-true {
            width: 100%;
            height: 10px;
            position: absolute;
            display: block;
            margin: auto;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
 
            &::before {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              left: 0;
              top: 0;
              background-color: #fff;
              transform: rotate(-70deg);
            }
 
            &::after {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              left: 0;
              bottom: 0;
              background-color: #fff;
              transform: rotate(70deg);
            }
          }
 
          .right-view-more-false {
            width: 100%;
            height: 10px;
            position: absolute;
            display: block;
            margin: auto;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
 
            &::before {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              right: 0;
              top: 0;
              background-color: #fff;
              transform: rotate(70deg);
            }
 
            &::after {
              display: block;
              height: 2px;
              width: 10px;
              content: "";
              position: absolute;
              right: 0;
              bottom: 0;
              background-color: #fff;
              transform: rotate(-70deg);
            }
          }
        }
      }
      // / 是否收起右侧边栏的图标
 
      // ^ 右侧拖动条
      .right-resize-bar {
        position: relative;
        display: flex;
        align-items: center;
        width: 7px;
        height: 100%;
        background-color: rgb(255, 255, 255);
        cursor: col-resize;
        user-select: none;
        transition: all ease 0.3s;
        font-size: 20px;
        color: #40485c;
 
        &:hover {
          color: #fff !important;
          background-color: #5e7ce0 !important;
        }
      }
      // / 右侧拖动条
 
      // ^ 右侧区域
      .right-area-box {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background-color: #f8f8f8;
      }
      // / 右侧区域
    }
    /* ---- / 右边 ---- */
  }
</style>

二、运行效果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Vue3实现鼠标按下某个元素进行拖动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能 的相关文章

  • lpad用法 oracle,oracle中lpad函数的用法详解

    oracle中lpad函数的用法详解 oracle中lpad的用法 pad翻译 填充 lpad函数 在字符串的左侧添加指定字符串 用法 www jb51 net lpad String 截取长度 添加的字符串 说是添加字符串也不准确 比较准
  • DCMTK读取dcm图片+opencv显示图片

    读取DCM格式图片中的一些基本信息 DcmFileFormat是最基本的文件对象 OFCondition是每一次操作的返回值 用来判断操作是否成功 所有的数据都存在DcmDataSet对象中 用getDataSet方法得到 void Loa
  • webpack(4版本)使用

    webpack简介 webpack 是一种前端资源构建工具 一个静态模块打包器 module bundler 在 webpack 看来 前 端的所有资源文件 js json css img less 都会作为模块处理 它将根据模块的依赖关系

随机推荐

  • 利用神经网络实现股票预测

    神经网络 NeuralNetworks 是一种用训练数据拟合目标函数的黑箱模型 只要数据量足够大 它可以拟合出输入到输出之间的任意函数关系 本篇教程我们将使用神经网络进行股市的预测 利用数据样本学习 得到相关因素预测股票走势 01 问题描述
  • 区块链+跨境支付有哪些优势?

    全球互联网的高速发展也带动了跨境电商的快速发展 跨境支付也瞬间成为第三方支付领域的一个风口 而将区块链技术应用在跨境支付领域也逐渐成为市场的热点需求 传统的跨境支付方式中间环节繁杂 费时又费力 而且跨境电商卖家在跨境支付环节 存在境外银行账
  • ModuleNotFoundError: No module named ‘fused_layer_norm_cuda‘

    No module named fused layer norm cuda Issue 161 NVIDIA apex GitHub 按照以下方式安装 可解决问题 apex 安装步骤 1 git clone https github com
  • android和iOS平台的崩溃捕获和收集

    通过崩溃捕获和收集 可以收集到已发布应用 游戏 的异常 以便开发人员发现和修改bug 对于提高软件质量有着极大的帮助 本文介绍了iOS和android平台下崩溃捕获和收集的原理及步骤 不过如果是个人开发应用或者没有特殊限制的话 就不用往下看
  • pycharm preparing workspace 项目打不开怎么办?

    屏幕一直显示 preparing workspace 无法打开项目时 找出保存最近项目信息的xml文件 Library Preferences Pycharm2019 2 options recentProjectsDirectories
  • Unity3D下如何采集camera场景数据并推送RTMP服务?

    Unity3D使用场景 Unity3D是非常流行的游戏开发引擎 可以创建各种类型的3D和2D游戏或其他互动应用程序 常见使用场景如下 游戏开发 Unity3D是一个广泛用于游戏开发的环境 适用于创建各种类型的游戏 包括动作游戏 角色扮演游戏
  • vue2.0+ 使用v-model 及报错解决办法;

    div div
  • 【WSL】使用WSL在Windows上安装Linux(Ubuntu20.04)

    文章目录 WSL 使用WSL在Windows上安装Linux Ubuntu20 04 一 环境说明 二 开启WSL功能 三 安装Linux子系统 四 升级内核 五 安装完成 六 Windows家庭版Hyper V功能开启 WSL 使用WSL
  • 通过SQL 语句删除重复记录并且只保留一条记录

    这里写自定义目录标题 1 重复字段 2 查询全部重复的数据 3 删除全部重复试题 4 查询表中多余重复试题 根据 depno 来判断 除了 rowid 最小的一个 4 1 第一种方法 4 2 第二种方法 4 3 第三种方法 5 删除表中多余
  • 同步IO、异步IO、阻塞IO、非阻塞IO、复用IO

    参考 同步IO 异步IO 作者 今天天气眞好 发布时间 2021 04 19 09 42 29 网址 https blog csdn net qq 51118175 article details 115857196 spm 1001 20
  • 讯为IMX6ULL-QT系统移植之busybox构建根文件系统

    一 BusyBox 工具下载 BusyBox 工具我们可以在其官网下载到 官网地址为 https busybox net 然后点击官网左侧 Get BusyBox 栏中的 Download Source 进入下载页面即可 先介绍等下要使用的
  • 硅谷悄然而起的流行:在管理上干掉CEO!

    本文系 Medium 于 2015 年 5 月 27 日举办的一次论坛活动回顾 在该活动上 员工嘉宾 Daryl Koopersmith 和 Jean Hsu 进行了关于 无差异自治 Holacracy 工作方式的分享演讲 关于Holacr
  • docker部署springboot,并且查看运行日志

    docker部署springboot 默认已经安装好docker 第一步 构建镜像 创建Dockerfile文件 文件内容如下 FROM frolvlad alpine oraclejdk8 slim VOLUME tmp ADD inde
  • 静态代码块、动态代码块、构造方法的优先级

    执行优先级 静态代码块 gt 动态代码块 gt 构造方法 代码案例 特殊情况 静态变量赋值new public class Main2 Main2 System out println hello world private static
  • 【算法】模拟,高精度

    高精度加法 P1601 A B Problem 高精 洛谷 计算机科学教育新生态 luogu com cn 思路就是模拟 值得注意的就是要用字符串类型输入 存进自己的int数组时要倒着存 因为如果是正着存的话 进位会有点trouble 时间
  • 机器学习:隐马尔可夫模型(HMM)

    后续会回来补充代码 1 隐马尔可夫模型 隐马尔可夫模型 Hidden Markov Model HMM 是可用于标注问题的统计学模型 描述由隐藏的马尔可夫链随机生成观测序列的过程 1 1 数学定义 隐马尔可夫模型是关于时序的概率模型 描述由
  • How to Connect Power Switches

    原文链接 https vlsiconceptsforyou blogspot com 2020 05 how to connect power switches html Wednesday May 20 2020 How to Conne
  • Python爱心代码

    效果展示 代码自取 from tkinter import from math import log sin cos pi import random 新建画布尺寸大小 CANVAS WIDTH 640 CANVAS HEIGHT 480
  • GBN,SR,TCP区别

    GBN 回退N go back N 如果某个报文段没有被正确的接收 那么从这个报文段到后面的报文段都要重新发送 返回的ACK采用剋及确认的机制 也就是说如果GBN返回的ACK 3 也就是说3报文段和3 之前的报文段都被正确地接收了 SR 接
  • 基于Vue3实现鼠标按下某个元素进行拖动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能

    前言 其原理主要是利用JavaScript中的鼠标事件来控制CSS样式 大致就是监听某个DOM元素的鼠标按下事件 以及按下之后的移动事件和松开事件 在鼠标按下且移动过程中 可实时获得鼠标的X轴坐标的值 通过简单计算 可计算出目标元素的宽度