周口市网站建设_网站建设公司_留言板_seo优化
2025/12/25 2:40:59 网站建设 项目流程

日常开发中经常遇到需要手动调整内容区大小的场景,比如侧边栏、弹窗、报表面板等。分享一个我写的「拖拽调整大小指令」,支持自定义最小尺寸、拖拽手柄样式,能监听尺寸变化

📌 先看效果

🛠 核心代码解析

指令文件directives/resizable-full.js,关键部分:

1. 指令钩子:初始化 + 更新 + 清理

Vue 指令的 3 个核心钩子,保证指令的生命周期完整:

js

export 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负责移除所有手柄元素和
事件监听器,指令解绑时必执行:

js

function 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; } }

🚀 如何使用?

  1. 全局注册指令(main.js):

js

import resizableFull from './directives/resizable-full'; Vue.directive('resizable-full', resizableFull);

2.页面中使用

vue

<template> <!-- 给需要拖拽的元素加指令 --> <div v-resizable-full="{ minWidth: 300, // 最小宽度 minHeight: 200, // 最小高度 handleSize: 10, // 手柄大小 handleColor: '#409eff', // 手柄颜色 onResize: handleResize // 拖拽结束回调 }" style="position: relative; width: 400px; height: 300px; border: 1px solid #eee;" > 我是可拖拽调整大小的内容区~ </div> </template> <script> export default { methods: { // 拖拽结束,拿到最新尺寸 handleResize({ width, height }) { console.log('新尺寸:', width, height); } } }; </script>

💡 关键注意点(避坑)

  1. 目标元素必须设position: relative/absolute/fixed:因为手柄是绝对定位,依赖父元素的定位;
  2. 事件绑在 document 上:拖拽时鼠标可能移出目标元素,绑在 document 上才不会断;
  3. 一定要清理事件 / 元素:指令解绑时执行cleanupResizable,避免内存泄漏;
  4. 最小尺寸限制:通过minWidth/minHeight避免元素被拖到太小,影响体验。

🎨 扩展玩法

  1. 解开注释的其他 7 个方向手柄,实现全方向拖拽;
  2. 给手柄加 hover 提示(比如 “拖拽调整大小”);
  3. 支持拖拽时实时触发回调(不止结束时);
  4. 自定义手柄样式(比如改成虚线、加图标)。

📝 总结

这个自定义指令核心是「创建拖拽手柄 + 监听鼠标事件 + 计算尺寸变化」,逻辑不复杂,可以根据自己的业务场景定制。亲测报表和弹窗都很适用~

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询