通过拖拽动态调整div的大小

最近遇到一个需求,页面展示两块内容,需要通过拖拽可以动态改变大小,如下图:
请添加图片描述

  • 实现思路:其实就是改变div样式的width,本质上就是Dom操作。

  • 完整代码:(基于vue2项目实践)

<template>
  <div class="box" ref="boxRef">
    <div class="left" ref="leftRef">
      左侧内容,默认展示30%,默认最小宽度200px
    </div>
    <div class="resize" ref="resizeRef"></div>
    <div class="right" ref="rightRef">
      右侧内容,默认展示70%,默认最小宽度200px
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  mounted() {
    this.handleResize();
  },
  methods: {
    handleResize(leftMinWidth = 200, rightMinWidth = 200) {
      // 获取Dom节点
      const boxDom = this.$refs.boxRef,
        leftDom = this.$refs.leftRef,
        resizeDom = this.$refs.resizeRef,
        rightDom = this.$refs.rightRef;
      resizeDom.onmousedown = e => {
        const startX = e.clientX; // 记录坐标起始位置
        leftDom.left = leftDom.offsetWidth; // 左边元素起始宽度
        document.onmousemove = e => {
          const endX = e.clientX; // 鼠标拖动的终止位置
          let moveLen = leftDom.left + (endX - startX); // 移动的距离 =  endX - startX,左边区域最后的宽度 = resizeDom.left + 移动的距离
          const maxWidth = boxDom.clientWidth - resizeDom.offsetWidth; // 左右两边区域的总宽度 = 外层容器宽度 - 中间区域拖拉框的宽度
          // 限制左边区域的最小宽度为 leftMinWidth
          if (moveLen < leftMinWidth) {
            moveLen = leftMinWidth;
          }
          // 右边区域最小宽度为 rightMinWidth
          if (moveLen > maxWidth - rightMinWidth) {
            moveLen = maxWidth - rightMinWidth;
          }
          leftDom.style.width = (moveLen / maxWidth) * 100 + "%"; // 设置左边区域的宽度,通过换算为百分比的形式,实现窗体放大缩小自适应
          rightDom.style.width = ((maxWidth - moveLen) / maxWidth) * 100 + "%"; // 右边区域 = 总大小 - 左边宽度 - 拖动条宽度
        };
        document.onmouseup = () => {
          document.onmousemove = null;
          document.onmouseup = null;
          resizeDom.releaseCapture && resizeDom.releaseCapture(); // 鼠标捕获释放
        };
        resizeDom.setCapture && resizeDom.setCapture(); // 启用鼠标捕获
        return false;
      };
    }
  }
};
</script>

<style lang="less" scoped>
.box {
  width: 100%;
  height: 300px;
  display: flex;
}
.left {
  width: 30%;
  background-color: #f1eab3;
  border: 1px solid #dcdfe6;
}
.resize {
  position: relative;
  width: 5px;
  cursor: col-resize;
  background-size: cover;
  background-position: center;
  &:hover {
    background-color: #45a3ff;
  }
}
.right {
  width: 70%;
  background-color: #b5ef8f;
  border: 1px solid #dcdfe6;
}
</style>
  • 扩展:同时支持上下/左右拖拽
    请添加图片描述

  • 实现原理和左右拖拽是一样的,只不过改变的样式是divheight

  • 完整代码如下:

<template>
  <div class="box" ref="boxRef" id="box">
    <div class="left" ref="leftRef">
      左侧,默认width=30%,minWidth=200px
    </div>
    <div class="resize" ref="resizeRef"></div>
    <div class="right" ref="rightRef">
      <div class="top" ref="topRef">
        右侧,默认width=70%,minWidth=200px,头部区域,默认minHeight=50px
      </div>
      <div class="resizeY" ref="resizeYRef"></div>
      <div class="content" ref="contentRef">
        右侧,默认width=70%,minWidth=200px,内容区域,默认minHeight=50px
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  mounted() {
    this.handleResize();
    this.handleYResize();
  },
  methods: {
    handleResize(leftMinWidth = 200, rightMinWidth = 200) {
      // 获取Dom节点
      const boxDom = this.$refs.boxRef,
        leftDom = this.$refs.leftRef,
        resizeDom = this.$refs.resizeRef,
        rightDom = this.$refs.rightRef;
      resizeDom.onmousedown = e => {
        const startX = e.clientX; // 记录坐标起始位置
        leftDom.left = leftDom.offsetWidth; // 左边元素起始宽度
        document.onmousemove = e => {
          const endX = e.clientX; // 鼠标拖动的终止位置
          let moveLen = leftDom.left + (endX - startX); // 移动的距离 =  endX - startX,左边区域最后的宽度 = resizeDom.left + 移动的距离
          const maxWidth = boxDom.clientWidth - resizeDom.offsetWidth; // 左右两边区域的总宽度 = 外层容器宽度 - 中间区域拖拉框的宽度
          // 限制左边区域的最小宽度为 leftMinWidth
          if (moveLen < leftMinWidth) {
            moveLen = leftMinWidth;
          }
          // 右边区域最小宽度为 rightMinWidth
          if (moveLen > maxWidth - rightMinWidth) {
            moveLen = maxWidth - rightMinWidth;
          }
          leftDom.style.width = (moveLen / maxWidth) * 100 + "%"; // 设置左边区域的宽度,通过换算为百分比的形式,实现窗体放大缩小自适应
          rightDom.style.width = ((maxWidth - moveLen) / maxWidth) * 100 + "%"; // 右边区域 = 总大小 - 左边宽度 - 拖动条宽度
        };
        document.onmouseup = () => {
          document.onmousemove = null;
          document.onmouseup = null;
          resizeDom.releaseCapture && resizeDom.releaseCapture(); // 鼠标捕获释放
        };
        resizeDom.setCapture && resizeDom.setCapture(); // 启用鼠标捕获
        return false;
      };
    },
    handleYResize(minTopHeight = 50, minContentHeight = 50) {
      const boxDom = this.$refs.boxRef,
        topDom = this.$refs.topRef,
        resizeDom = this.$refs.resizeYRef,
        contentDom = this.$refs.contentRef;
      resizeDom.onmousedown = e => {
        const startY = e.clientY;
        resizeDom.top = resizeDom.offsetHeight;
        document.onmousemove = e => {
          const endY = e.clientY;
          let moveLen = resizeDom.top + (endY - startY);
          const maxHeight = boxDom.clientHeight - resizeDom.offsetHeight;
          if (moveLen < minTopHeight) {
            moveLen = minTopHeight;
          }
          if (moveLen > maxHeight - minContentHeight) {
            moveLen = maxHeight - minContentHeight;
          }
          topDom.style.height = (moveLen / maxHeight) * 100 + "%";
          contentDom.style.height =
            ((maxHeight - moveLen) / maxHeight) * 100 + "%";
        };
        document.onmouseup = () => {
          document.onmousemove = null;
          document.onmouseup = null;
          resizeDom.releaseCapture && resize.releaseCapture();
        };
        resizeDom.setCapture && resizeDom.setCapture();
        return false;
      };
    }
  }
};
</script>

<style lang="less" scoped>
.box {
  display: flex;
  width: 100%;
  height: 300px;
}
.left {
  width: 30%;
  background-color: #f1eab3;
  border: 1px solid #dcdfe6;
}
.resize {
  position: relative;
  width: 3px;
  height: 100%;
  cursor: col-resize;
  background-size: cover;
  background-position: center;
  &:hover {
    background-color: #45a3ff;
  }
}
.right {
  width: 70%;
  // background-color: #b5ef8f;
  // border: 1px solid #dcdfe6;
  overflow: hidden;
  .top {
    height: 20%;
    background-color: #b5ef8f;
    border: 1px solid #dcdfe6;
  }
  .resizeY {
    position: relative;
    height: 3px;
    cursor: row-resize;
    &:hover {
      background-color: #45a3ff;
    }
  }
  .content {
    height: 80%;
    background: #abc8ea;
    border: 1px solid #dcdfe6;
  }
}
</style>

知识点

1、属性:clientWidth / offsetWidth

clientWidth只读属性,返回元素的内部宽度,该属性包括内边距,但不包括垂直滚动条(如果有)、边框和外边距。

offsetWidth 只读属性,返回元素的布局宽度。该属性包含元素的边框、水平线上的内边距、竖直方向滚动条(如果有的话)、以及CSS设置的宽度(width)值。

例如:一个有滚动条的div
在这里插入图片描述
(clientWidth) 205 = 185(实际width) + 10 (padding) + 10 (padding)
(offsetWidth) 240 = 185(实际width) + 10 (padding) + 10 (padding) + 10 (border) + 10 (border) + 15 (scrollWidth)

2、方法:setCapture() / releaseCapture()

调用SetCapture()函数后,能够捕获鼠标相关事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout,一般使用onmousemoveonmouseup两个事件。

当不再需要继续获得鼠标消息就要应该调用releaseCapture()释放掉,否则别的线程想调用就会失败。所以:setCapture()releaseCapture()必须成对呈现!

3、 鼠标事件

事件名称含义
mousedown鼠标按下
mouseup鼠标释放
click左键单击
dbclick左键双击
mousemove鼠标移动
mouseover鼠标经过
mouseout鼠标滑出
mouseenter鼠标进入
mouseleave鼠标离开
contextmenu右键菜单

1)执行顺序:mousedown => mouseup => click
2)mouseover 和 mouseout子元素也会触发,可以冒泡触发。mouseenter 和mouseleave是针对侦听的对象触发,阻止了冒泡。
3)阻止鼠标的默认事件

e.preventDefault()
e.returnValue = false; // IE8 及以下兼容写法
return false; // IE兼容写法,只用作on事件阻止默认事件
  • 事件对象属性:clientX / clientY 点击位置距离当前body可视区域的x,y 坐标。

4、鼠标样式

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/559939.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

23年新算法,SAO-SVM,基于SAO雪消融算法优化SVM支持向量机回归预测(多输入单输出)-附代码

SAO-SVM是一种基于SAO雪消融算法优化的支持向量机&#xff08;SVM&#xff09;回归预测方法&#xff0c;适用于多输入单输出的情况。下面是一个简要的概述&#xff0c;包括如何使用SAO-SVM进行回归预测的步骤&#xff1a; 步骤&#xff1a; 1. 数据准备&#xff1a; 收集并准…

API 自动化测试的实践与技巧

在软件开发的快速迭代过程中&#xff0c;及时准确地进行测试变得越来越重要。Apifox 作为一款先进的 API 接口管理和自动化测试平台&#xff0c;为测试人员提供了强大的工具来适应这种变化。以下是使用 Apifox 进行 自动化测试 的实际指南。 1. 接口管理与自动化测试设置 在 …

增强现实(AR)开发框架

增强现实&#xff08;AR&#xff09;开发框架为开发者提供了构建AR应用程序所需的基本工具和功能。它们通常包括3D引擎、场景图、输入系统、音频系统和网络功能。以下是一些流行的AR开发框架。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流…

证照之星是免费的吗?证照之星怎么使用?证照之星XE v7.0 免费版 证照之星版本区别

证件照是每个人都必须用到的&#xff0c;并且机构不同&#xff0c;对于证件照的规格也不同。为了提升我们的效率&#xff0c;我们会使用证照之星这类证件照编辑软件对证件照进行编辑&#xff0c;那么这种类型的证件照编辑软件应该如何使用&#xff0c;收费标准又是怎么样的呢&a…

C++中的运算符

一、算数运算符 1.1 加减乘除取模 #include <iostream> using namespace std;int main() {//加减乘除int a1 10;int b1 5;cout << "a1 b1 " << a1 b1 << endl;cout << "a1 - b1 " << a1 - b1 << endl;co…

安装zlmediakit和wvp-pro

通过docker安装zlmediakit&#xff0c;并单独启动wvp-pro.jar - zlmediakit安装 zlmediakit安装比较依赖环境和系统配置&#xff0c;所以这里直接使用docker的方式来安装。 docke pull拉取镜像 docker pull zlmediakit/zlmediakit:master使用下边命令先运行起来 sudo docke…

【深度学习实战(12)】训练之模型参数初始化

在深度学习模型的训练中&#xff0c;权重的初始值极为重要。一个好的初始值&#xff0c;会使模型收敛速度提高&#xff0c;使模型准确率更精确。一般情况下&#xff0c;我们不使用全0初始值训练网络。为了利于训练和减少收敛时间&#xff0c;我们需要对模型进行合理的初始化。 …

图文教程 | 2024年最新Typora激活使用教程合集

前言 汇总一下网上的三种方法。 &#x1f4e2;博客主页&#xff1a;程序源⠀-CSDN博客 &#x1f4e2;欢迎点赞&#x1f44d;收藏⭐留言&#x1f4dd;如有错误敬请指正&#xff01; 关于安装教程&#xff1a;http://t.csdnimg.cn/SCIQ8http://t.csdnimg.cn/SCIQ8自行跳转安装 一…

Ugee手写板Ex08 S在不同软件中的设置

手写笔的结构 功能对应于鼠标的作用笔尖鼠标左键上面第一个键鼠标右键&#xff08;效果有时候也不完全等同&#xff09;上面第二个键鼠标中键 以下测试的软件版本 软件版本windows10WPS2024春季16729Office2007SimpleTex0.2.5Ex08 S驱动版本4.2.4.231109 WPS-word ①点击审…

Zabbix 监控软件(一)

通常我们服务搭建成功 但不清楚服务器的运行状况&#xff0c;这时候就需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果&#xff0c;和网站的健康状态。 利用一个优秀的监控软件&#xff0c;我们可以: ●通过一个友好的界…

互联网技术知识点总览——操作系统知识点框架图

简介 本文对操作系统的知识点整体框架进行梳理和分享如下&#xff1a;

智能生活新体验:小米香薰加湿器技术解码

在现代家居生活中&#xff0c;科技与舒适性日益交织&#xff0c;智能家居产品成为提升生活品质的重要工具。小米香薰加湿器作为一款集科技与生活美学于一体的产品&#xff0c;其独特的设计和多功能性受到了广泛欢迎。今天&#xff0c;我们就来详细拆解这款融合了科技与香薰元素…

如何搭建线下陪玩系统(本地伴游、多玩圈子)APP小程序H5多端前后端源码交付,支持二开!

一、卡顿的优化方法 1、对陪玩系统源码中流媒体传输的上行进行优化&#xff0c;通过提升推流端的设备性能配置、推流边缘CDN节点就近选择等方式解决音视频数据源流的卡顿。 2、对陪玩系统源码中音视频数据的下载链路进行优化&#xff0c;通过选择更近更优质的CDN边缘节点来减少…

OpenHarmony实战开发-如何实现发布图片评论功能。

介绍 本示例将通过发布图片评论场景&#xff0c;介绍如何使用startAbilityForResult接口拉起相机拍照&#xff0c;并获取相机返回的数据。 效果图预览 使用说明 通过startAbilityForResult接口拉起相机&#xff0c;拍照后获取图片地址。 实现思路 1.创建CommentData类&…

Docker Desktop打开一直转圈的解决办法

安装Docker Desktop之前确保你的Hyper-V已经打开 开启后需要重新安装重新安装重新安装这是最关键的一步&#xff0c;博主自己看了很多教程&#xff0c;最后试着重装了一下解决了 安装DockerDesktop的时候我的电脑根本就没有Hyper-V这个功能选项&#xff0c;可能是这个问题 如…

RLHF强化学习对其算法:PPO、DPO、ORPO

参考&#xff1a; https://blog.csdn.net/baoyan2015/article/details/135287298 https://cloud.tencent.com/developer/article/2409553 最新的llama3是PPO、DPO两种方法使用 人类反馈强化学习 (RLHF)&#xff0c;它利用人类偏好和指导来训练和改进机器学习模型&#xff1a; …

ColBERT和ColBERTv2:兼具Bi-encoder和cross-encoder优势的多向量排序模型

文章目录 简介ColBERTColBert 原理ColBERT如何训练ColBERT 如何使用离线索引用ColBERT 实现top-k Re-ranking用ColBERT 实现top-k 端到端的检索 ColBERTv2ColBERTv2原理SupervisionRepresentation IndexingRetrieval 总结参考资料 简介 ColBERT是一种多向量排序模型&#xff0…

centos7安装mysql5.7笔记

1 配置yum仓库 1.1更新密钥 #更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 1.2 下载使用wget命令下载MySQL的repo文件 #下载使用wget命令下载MySQL的repo文件 wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 2 使用…

我为什么想成为一名程序员

#为什么你选择成为一名程序员# 目录 原因&#xff1a; 后续选择&#xff1a; 结尾&#xff1a; 原因&#xff1a; 本人是一个00后&#xff0c;出生在农村当时经济相对来说比较落后&#xff0c;村里面基本上都没几个人有手机。当时有些小伙伴他们拿着自己大人的手机在那里玩…

CS61B sp21fall Project02 Gitlet

Project02 Gitlet 一、项目简介二、Git和Gitlet2.1 Git简介2.2 Gitlet简介 三、框架设计3.1 Blobs3.2 Trees3.3 Commits 四、.Gitlet文件结构设计4.1 .git文件架构4.1.1 重点介绍index&#xff08;VSCode中无法查看&#xff0c;会乱码&#xff09;objects&#xff08;VSCode中无…
最新文章