Vue 3 中可手写鼠标事件实现拖拽调宽,或用 vue3-draggable-resizable 支持多向缩放;需注意 flex-basis 替代 width、节流防重排、触摸适配及事件冒泡处理。

在 Vue 3 单文件组件中实现拖拽调整容器宽度,核心是监听鼠标事件、动态更新目标元素的 width(或 flex-basis),并配合 CSS 布局机制(如 flex)让相邻区域自适应。不依赖第三方 UI 库也能轻量实现,适合侧边栏、分栏布局等场景。
用原生逻辑手写拖拽调整宽度
适用于左右两栏结构(如左侧菜单 + 主内容区),中间加一个可拖拽的分割手柄:
- 给分割手柄(
<div class="resize-handle">)绑定@mousedown - 在
startDrag中记录初始鼠标位置和左侧容器当前宽度 - 监听
document @mousemove计算拖动偏移,更新左侧容器的ref宽度值(如leftWidth) - 用
@mouseup或document @mouseup清除监听,防止拖出区域失效 - CSS 上用
display: flex+flex: 0 0 v-model:width保证右侧自动撑满剩余空间
使用 vue3-draggable-resizable 快速启用
若需同时支持拖拽位移 + 多方向缩放(不只是宽度),推荐封装成熟的 vue3-draggable-resizable:
- 安装:
npm install vue3-draggable-resizable - 注册为全局组件(
main.js)并引入样式:import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css' - 模板中指定仅水平缩放:
:resizable="true" :handles="['e']"(e表示右边缘句柄) - 绑定响应式宽高:
v-model:w="containerWidth",其他方向设为false或省略 - 加
:parent="true"可限制拖拽缩放不超出父容器边界
适配 flex 布局的宽度联动技巧
当容器本身是 flex 子项时,直接改 width 可能被 flex 规则覆盖。更稳妥的做法是:
立即学习“前端免费学习笔记(深入)”;
- 用
flex-basis替代width控制基础尺寸(:style="{ 'flex-basis': leftWidth + 'px' }") - 确保父容器设
display: flex,且右侧区域设flex: 1或flex: auto - 添加最小/最大宽度限制:
:minW="200" :maxW="600"(搭配第三方组件)或手写逻辑中做Math.clamp判断 - 避免频繁重排:对 resize handler 使用
throttle(例如 Lodash 的throttle或自行节流)
处理常见问题
实际开发中容易卡住的点:
-
拖拽手柄没反应:检查是否设置了
user-select: none和cursor: col-resize,并确认事件绑定在正确层级 -
拖动后宽度跳变:确保初始
leftWidth与 DOM 渲染后的实际宽度一致(可用onMounted+getBoundingClientRect()初始化) -
移动端不生效:需额外监听
touchstart/touchmove/touchend,或使用vue3-draggable-resizable内置的 touch 支持 -
父子嵌套拖拽冲突:给手柄加
pointer-events: auto,并阻止事件冒泡(@mousedown.stop)


















