介绍
实现功能:可视化标签拖拽,双击标签可修改标签内容
HTML结构
html
<div class="box" v-move>
<div class="header">标签1</div>
<div @dblclick="startEditing" v-if="!isEditing">{{content}}</div>
<input type="text" v-model="editedContent" @blur = 'stopEditing' v-if="isEditing">
</div>
一个大DIV包含里面存放两个DIV一个input
header为头部标签名称
内容区域绑定双击鼠标事件,触发开始修改事件(startEditing),使用v-if进行标签的显示和隐藏操作
input标签,事件绑定为修改内容,绑定获取焦点事件(@blue="stopEditing"),并且绑定和内容区域一样的变量用来控制显示隐藏,一方为显示另一方必定为隐藏
TS部分
typescript
import { Directive, DirectiveBinding } from "vue";
const vMove: Directive<any, void> = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
// 创建一个变量 moveElement,表示 DOM 元素的子元素(假设这是要拖动的元素)
const moveElement: HTMLDivElement = el.firstElementChild as HTMLDivElement;
// 鼠标按下事件处理函数
const mouseDown = (e: MouseEvent) => {
// 计算鼠标相对于元素的偏移量
const X = e.clientX - el.offsetLeft;
const Y = e.clientY - el.offsetTop;
// 鼠标移动事件处理函数
const move = (e: MouseEvent) => {
// 更新元素的位置,实现拖动效果
el.style.left = e.clientX - X + "px";
el.style.top = e.clientY - Y + "px";
};
// 添加鼠标移动事件监听器
document.addEventListener("mousemove", move);
// 添加鼠标松开事件监听器,用于停止拖动
document.addEventListener("mouseup", () => {
document.removeEventListener("mousemove", move);
});
};
// 将鼠标按下事件处理函数添加到元素上
moveElement.addEventListener("mousedown", mouseDown);
},
};
采用自定义指令进行设置移动组件,Directive 和 DirectiveBinding:这是Vue.js中用于自定义指令的一些类型和功能。自定义指令允许你在DOM元素上附加自定义行为。Directive 是自定义指令的基本类型,而 DirectiveBinding 是与指令绑定的数据的类型。
上述代码定义了一个名为 vMove 的自定义指令,它会在元素上附加拖动行为。当鼠标在 moveElement(元素的子元素)上按下时,启动拖动操作,通过鼠标移动事件更新元素的位置,并在鼠标松开时停止拖动。这个自定义指令可以在Vue.js应用中使用,将其添加到需要拖动的元素上,以实现拖拽功能。
typescript
<script setup lang="ts">
// 导入 Vue 和自定义指令相关的模块
import { ref, Directive, DirectiveBinding } from "vue";
// 自定义指令 vMove 的实现
const vMove: Directive<any, void> = (el: HTMLElement, binding: DirectiveBinding) => {
// 获取需要移动的 DOM 元素,假设它是传入元素的第一个子元素
let moveElement: HTMLElement = el.firstElementChild as HTMLDivElement;
console.log(moveElement);
// 鼠标按下事件处理函数
const mouseDown = (e: MouseEvent) => {
// 计算鼠标点击位置相对于元素左上角的偏移量
let X = e.clientX - el.offsetLeft;
let Y = e.clientY - el.offsetTop;
// 鼠标移动事件处理函数
const move = (e: MouseEvent) => {
console.log(e);
// 更新元素的位置,实现拖动效果
el.style.left = e.clientX - X + "px";
el.style.top = e.clientY - Y + "px";
};
// 添加鼠标移动事件监听器,以便拖动元素
document.addEventListener("mousemove", move);
// 添加鼠标松开事件监听器,停止拖动
document.addEventListener("mouseup", () => {
document.removeEventListener("mousemove", move);
});
};
// 将鼠标按下事件处理函数添加到移动元素上
moveElement.addEventListener("mousedown", mouseDown);
console.log(binding);
};
// 使用 ref 创建响应式数据
const content = ref('内容'); // 原始内容
const isEditing = ref(false); // 是否处于编辑模式
const editedContent = ref(''); // 编辑后的内容
// 进入编辑模式
const startEditing = () => {
isEditing.value = true;
editedContent.value = content.value; // 将原始内容设置为编辑后的内容
}
// 退出编辑模式
const stopEditing = () => {
isEditing.value = false;
content.value = editedContent.value; // 保存编辑后的内容
}
</script>
<template>
<div class="box" v-move>
<div class="header">标签1</div>
<!-- 使用双击事件触发编辑模式 -->
<div @dblclick="startEditing" v-if="!isEditing">{{ content }}</div>
<!-- 编辑模式下显示输入框 -->
<input type="text" v-model="editedContent" @blur="stopEditing" v-if="isEditing">
</div>
</template>
<style scoped>
.box {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border: 3px solid;
background: #f59c09;
.header {
height: 20px;
background: #f59c09;
color: white;
}
}
</style>