2026/1/10 15:48:03
网站建设
项目流程
互站网源码网站,seodg官网,企业建设网站能否报销,河南网站建设找工作日常开发中经常遇到需要手动调整内容区大小的场景#xff0c;比如侧边栏、弹窗、报表面板等。分享一个我写的「拖拽调整大小指令」#xff0c;支持自定义最小尺寸、拖拽手柄样式#xff0c;能监听尺寸变化#x1f4cc; 先看效果#x1f6e0; 核心代码解析指令文件 directi…日常开发中经常遇到需要手动调整内容区大小的场景比如侧边栏、弹窗、报表面板等。分享一个我写的「拖拽调整大小指令」支持自定义最小尺寸、拖拽手柄样式能监听尺寸变化 先看效果 核心代码解析指令文件directives/resizable-full.js关键部分1. 指令钩子初始化 更新 清理Vue 指令的 3 个核心钩子保证指令的生命周期完整jsexport default { bind(el, binding) { // 指令绑定时初始化拖拽功能 initResizable(el, binding); }, update(el, binding) { // 禁用状态变化时重新初始化 if (binding.value?.disabled ! binding.oldValue?.disabled) { cleanupResizable(el); // 先清理旧的 initResizable(el, binding); // 再初始化新的 } }, unbind(el) { // 指令解绑时清理所有手柄和事件避免内存泄漏cleanupResizable(el); } };2. 初始化拖拽创建手柄 核心逻辑initResizable是核心函数主要做 2 件事创建拖拽手柄、写拖拽逻辑。1创建拖拽手柄我只保留了「右下角」的拖拽手柄其他方向注释掉了需要的话自己解开样式可自定义js// 定义手柄配置只留了bottom-right const handles [ { dir: bottom-right, style: { bottom: 0, right: 0, cursor: nwse-resize } } ]; // 循环创建手柄元素 handles.forEach(handleConf { const handle document.createElement(div); handle.className resizable-handle resizable-handle--${handleConf.dir}; handle.dataset.dir handleConf.dir; // 手柄样式小方块、半透明、hover高亮 Object.assign(handle.style, { position: absolute, width: ${handleSize}px, height: ${handleSize}px, background: handleColor, opacity: 0.6, zIndex: 999, transition: opacity 0.2s, ...handleConf.style }); // hover时手柄高亮 handle.addEventListener(mouseenter, () handle.style.opacity 1); handle.addEventListener(mouseleave, () handle.style.opacity 0.6); el.appendChild(handle); // 把手柄加到目标元素上 el._resizableConfig.handles.push(handle); // 存起来方便后续清理 });2拖拽核心逻辑分 3 步按下鼠标记录初始状态→ 移动鼠标计算新尺寸→ 松开鼠标触发回调 清理js// 1. 按下鼠标记录初始位置和尺寸 const mouseDownHandler (e) { const handle e.target.closest(.resizable-handle); if (!handle) return; e.stopPropagation(); e.preventDefault(); const dir handle.dataset.dir; const rect el.getBoundingClientRect(); // 获取元素当前位置和尺寸 // 存初始状态鼠标位置、元素尺寸/位置 startState { dir, startX: e.clientX, startY: e.clientY, startWidth: rect.width, startHeight: rect.height }; // 绑定移动/松开事件绑在document上避免拖拽时鼠标移出元素失效 document.addEventListener(mousemove, onMouseMove); document.addEventListener(mouseup, onMouseUp); }; // 2. 移动鼠标计算新宽高并赋值 const onMouseMove (e) { if (!startState) return; const { dir, startX, startY, startWidth, startHeight } startState; let newWidth startWidth; let newHeight startHeight; // 只处理右下角拖拽宽高都增加 if (dir bottom-right) { newWidth startWidth (e.clientX - startX); newHeight startHeight (e.clientY - startY); } // 限制最小宽高避免拖到太小 newWidth Math.max(minWidth, newWidth); newHeight Math.max(minHeight, newHeight); // 给元素设置新尺寸 el.style.width ${newWidth}px; el.style.height ${newHeight}px; }; // 3. 松开鼠标触发回调清理事件 const onMouseUp () { // 拖拽结束触发自定义回调返回最新尺寸 if (startState el._resizableConfig.onResize) { el._resizableConfig.onResize({ width: parseInt(el.style.width), height: parseInt(el.style.height) }); } startState null; // 移除事件避免重复绑定 document.removeEventListener(mousemove, onMouseMove); document.removeEventListener(mouseup, onMouseUp); }; // 给元素绑定按下事件 el.addEventListener(mousedown, mouseDownHandler);3. 清理函数避免内存泄漏cleanupResizable负责移除所有手柄元素和事件监听器指令解绑时必执行jsfunction cleanupResizable(el) { if (el._resizableConfig) { // 移除所有手柄 el._resizableConfig.handles.forEach(handle { if (handle.parentNode el) el.removeChild(handle); }); // 移除所有事件监听器 el.removeEventListener(mousedown, el._resizableConfig.mouseDownHandler); document.removeEventListener(mousemove, el._resizableConfig.mouseMoveHandler); document.removeEventListener(mouseup, el._resizableConfig.mouseUpHandler); // 删除配置释放内存 delete el._resizableConfig; } } 如何使用全局注册指令main.jsjsimport resizableFull from ./directives/resizable-full; Vue.directive(resizable-full, resizableFull);2.页面中使用vuetemplate !-- 给需要拖拽的元素加指令 -- div v-resizable-full{ minWidth: 300, // 最小宽度 minHeight: 200, // 最小高度 handleSize: 10, // 手柄大小 handleColor: #409eff, // 手柄颜色 onResize: handleResize // 拖拽结束回调 } styleposition: relative; width: 400px; height: 300px; border: 1px solid #eee; 我是可拖拽调整大小的内容区 /div /template script export default { methods: { // 拖拽结束拿到最新尺寸 handleResize({ width, height }) { console.log(新尺寸, width, height); } } }; /script 关键注意点避坑目标元素必须设position: relative/absolute/fixed因为手柄是绝对定位依赖父元素的定位事件绑在 document 上拖拽时鼠标可能移出目标元素绑在 document 上才不会断一定要清理事件 / 元素指令解绑时执行cleanupResizable避免内存泄漏最小尺寸限制通过minWidth/minHeight避免元素被拖到太小影响体验。 扩展玩法解开注释的其他 7 个方向手柄实现全方向拖拽给手柄加 hover 提示比如 “拖拽调整大小”支持拖拽时实时触发回调不止结束时自定义手柄样式比如改成虚线、加图标。 总结这个自定义指令核心是「创建拖拽手柄 监听鼠标事件 计算尺寸变化」逻辑不复杂可以根据自己的业务场景定制。亲测报表和弹窗都很适用