
Vue 自定义指令:实现可拖拽缩放的容器
在日常开发中,我们可能会遇到需要用户通过拖拽调整布局大小的场景,例如分割面板、拖拽调整弹窗大小等功能。本文将介绍如何使用 Vue 自定义指令实现一个支持拖拽缩放的容器,并详细说明该指令的功能和使用方法。
指令功能概述
该指令通过拖拽分隔条,调整目标元素的宽度或高度,具备以下功能:
支持宽度或高度缩放:可以通过传递参数决定调整方向。
支持尺寸限制:可以设置最小尺寸(
minSize
)和最大尺寸(maxSize
)。步长调整:支持每次调整的像素步长,提供更精细或更灵敏的拖拽体验。
回调事件:支持在调整尺寸时触发父组件的回调,方便同步更新。
指令实现
以下是该指令的完整实现代码:
// src/directives/resize.ts
import type { Directive, DirectiveBinding } from "vue"; // 使用 type 引入
const resize: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
const direction = binding.arg || "height"; // 默认按高缩放
const step = binding.value?.step || 1; // 缩放的步长
const sensitivity = binding.value?.sensitivity || 1; // 缩放灵敏度
const minSize = binding.value?.minSize || 50; // 最小尺寸
const maxSize = binding.value?.maxSize || Infinity; // 最大尺寸
const parent = el.parentElement;
if (!parent) {
console.warn("resize directive requires the element to have a parent");
return;
}
// 创建分隔条
const divider = document.createElement("div");
divider.style.position = "absolute";
divider.style.background = "#ccc";
divider.style.cursor = direction === "width" ? "col-resize" : "row-resize";
divider.style[direction === "width" ? "right" : "bottom"] = "0";
divider.style[direction === "width" ? "width" : "height"] = "5px";
divider.style[direction === "width" ? "height" : "width"] = "100%";
divider.style.zIndex = "100";
el.appendChild(divider);
// 事件处理
let startPos = 0;
let startSize = 0;
const onMouseDown = (event: MouseEvent) => {
startPos = direction === "width" ? event.clientX : event.clientY;
startSize = direction === "width" ? el.offsetWidth : el.offsetHeight;
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
event.preventDefault();
};
const onMouseMove = (event: MouseEvent) => {
const currentPos = direction === "width" ? event.clientX : event.clientY;
const diff = (currentPos - startPos) * sensitivity;
let newSize = startSize + Math.round(diff / step) * step;
newSize = Math.max(minSize, Math.min(maxSize, newSize));
el.style[direction] = `${newSize}px`;
// 触发父组件绑定的回调
if (binding.value?.onResize) {
binding.value.onResize(newSize);
}
};
const onMouseUp = () => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
};
divider.addEventListener("mousedown", onMouseDown);
},
};
export default resize;
使用方法
1. 注册指令
在项目中全局注册指令:
// src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import resize from "./directives/resize";
const app = createApp(App);
app.directive("resize", resize);
app.mount("#app");
2. 模板中使用指令
使用 v-resize
指令可以轻松实现可拖拽缩放的容器。以下是一个示例:
<template>
<div class="resize-container" v-resize:height="{
step: 10,
sensitivity: 1,
minSize: 100,
maxSize: 500,
onResize: handleResize
}">
<p>拖拽调整高度</p>
</div>
</template>
<script setup>
function handleResize(newSize) {
console.log("当前尺寸:", newSize);
}
</script>
<style>
.resize-container {
width: 100%;
height: 300px;
position: relative;
background-color: #f0f0f0;
}
</style>
3. 参数说明
指令参数
适用场景
分割布局:例如左侧导航栏和右侧内容区域的宽度调整。
弹窗调整:拖拽调整弹窗的宽高。
动态面板:如代码编辑器与预览窗口的大小调整。
总结
通过本文提供的自定义指令,开发者可以轻松实现拖拽缩放功能,且具备灵活的定制化选项(如步长、灵敏度、尺寸限制等)。这种实现方式不仅减少了 DOM 操作,还能无缝地集成到 Vue 项目中,为用户提供更好的交互体验。
本文是原创文章,完整转载请注明来自 俞泊
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果