vue编写一个可拖动的模块,并可以和任何其他组件组合使用

server/2025/1/19 1:51:28/

实现思路

  1. 使用 Vue 的自定义指令(directive)来处理拖动逻辑。
  2. mounted 钩子中添加鼠标事件监听器,以实现拖动功能。
  3. unmounted 钩子中移除鼠标事件监听器,防止内存泄漏。

代码示例

<template><div v-draggable class="draggable-component"><slot></slot></div>
</template><script>javascript">
export default {name: 'DraggableComponent',directives: {draggable: {// 当绑定元素插入到 DOM 中时mounted(el) {let isDragging = false;let initialX, initialY;let offsetX = 0, offsetY = 0;const handleMouseDown = (e) => {isDragging = true;initialX = e.clientX - offsetX;initialY = e.clientY - offsetY;};const handleMouseMove = (e) => {if (isDragging) {offsetX = e.clientX - initialX;offsetY = e.clientY - initialY;el.style.transform = `translate3d(${offsetX}px, ${offsetY}px, 0)`;}};const handleMouseUp = () => {isDragging = false;};el.addEventListener('mousedown', handleMouseDown);document.addEventListener('mousemove', handleMouseMove);document.addEventListener('mouseup', handleMouseUp);// 在元素销毁时移除事件监听器el._removeEventListeners = () => {el.removeEventListener('mousedown', handleMouseDown);document.removeEventListener('mousemove', handleMouseMove);document.removeEventListener('mouseup', handleMouseUp);};},unmounted(el) {if (el._removeEventListeners) {el._removeEventListeners();}}}}
};
</script><style scoped>
.draggable-component {position: absolute;background-color: #f0f0f0;border: 1px solid #ccc;padding: 10px;cursor: move;
}
</style>

代码解释

  • 模板部分

    • <div v-draggable class="draggable-component">:使用自定义指令 v-draggable 使该 div 元素具有可拖动的功能。
    • <slot></slot>:使用插槽,允许其他组件或内容插入到这个可拖动的 div 中,从而实现与其他组件的组合使用。
  • 脚本部分

    • directives:定义了一个名为 draggable 的自定义指令。
      • mounted 钩子:
        • isDragging:用于标记是否正在拖动。
        • initialXinitialY:记录鼠标按下时的初始位置。
        • offsetXoffsetY:存储元素相对于初始位置的偏移量。
        • handleMouseDown:当鼠标按下时触发,标记为正在拖动,并记录初始位置。
        • handleMouseMove:当鼠标移动且正在拖动时触发,计算偏移量并更新元素的 transform 属性,使用 translate3d 进行元素的平移。
        • handleMouseUp:当鼠标松开时触发,标记为停止拖动。
        • 添加鼠标事件监听器:为元素添加 mousedown 事件监听器,为文档添加 mousemovemouseup 事件监听器。
        • el._removeEventListeners:存储一个函数,用于移除事件监听器。
      • unmounted 钩子:在元素销毁时调用 el._removeEventListeners 移除事件监听器,防止内存泄漏。

使用示例

<template><div id="app"><DraggableComponent><h1>可拖动的组件</h1><p>这是一个可以拖动的模块,并且可以和任何其他组件组合使用。</p><AnotherComponent></AnotherComponent></DraggableComponent></div>
</template><script>javascript">
import DraggableComponent from './DraggableComponent.vue';
import AnotherComponent from './AnotherComponent.vue';export default {name: 'App',components: {DraggableComponent,AnotherComponent}
};
</script>

解释

  • 首先,将 DraggableComponent 组件导入并注册。
  • 在模板中使用 DraggableComponent 组件,并在其内部使用插槽插入了一个 h1 元素、一个 p 元素和 AnotherComponent 组件,这样就实现了一个可拖动的组件,并且可以方便地与其他组件组合使用。

注意事项

  • 确保在 unmounted 钩子中移除事件监听器,以避免内存泄漏。
  • 该示例只是一个简单的实现,你可以根据需求扩展功能,例如限制拖动范围、添加拖动手柄等。

通过上述方法,你可以在 Vue 中实现一个可拖动的模块,并将其与任何其他组件进行组合使用。如果你需要更复杂的拖动功能,例如与其他组件进行交互或支持多个可拖动元素,可以考虑使用第三方库,如 vue-draggablevue-draggable-resizable。这些库提供了更丰富的功能和更强大的拖动、调整大小等操作。

还有其他方法实现可拖动模块吗?

另一种在 Vue 中实现可拖动模块的方法,使用 Vue 的 ref 和组件方法来处理拖动逻辑:

实现思路

  1. 使用 ref 获取元素引用。
  2. 在组件的 mounted 生命周期中添加鼠标事件监听器。
  3. 在鼠标按下、移动和松开时更新元素的位置。

代码示例

<template><div ref="draggable" class="draggable-component"><slot></slot></div>
</template><script>javascript">
export default {name: 'DraggableComponent',data() {return {isDragging: false,startX: 0,startY: 0,offsetX: 0,offsetY: 0};},mounted() {const draggable = this.$refs.draggable;const handleMouseDown = (e) => {this.isDragging = true;this.startX = e.clientX - this.offsetX;this.startY = e.clientY - this.offsetY;};const handleMouseMove = (e) => {if (this.isDragging) {this.offsetX = e.clientX - this.startX;this.offsetY = e.clientY - this.startY;draggable.style.transform = `translate3d(${this.offsetX}px, ${this.offsetY}px, 0)`;}};const handleMouseUp = () => {this.isDragging = false;};draggable.addEventListener('mousedown', handleMouseDown);document.addEventListener('mousemove', handleMouseMove);document.addEventListener('mouseup', handleMouseUp);// 在组件销毁时移除事件监听器this.$once('hook:beforeDestroy', () => {draggable.removeEventListener('mousedown', handleMouseDown);document.removeEventListener('mousemove', handleMouseMove);document.removeEventListener('mouseup', handleMouseUp);});}
};
</script><style scoped>
.draggable-component {position: absolute;background-color: #f0f0f0;border: 1px solid #ccc;padding: 10px;cursor: move;
}
</style>

代码解释

  • 模板部分

    • <div ref="draggable" class="draggable-component">:使用 ref 属性给 div 元素一个引用,方便在组件内部访问。
    • <slot></slot>:使用插槽,允许插入其他组件或内容。
  • 脚本部分

    • data 中存储拖动所需的状态:
      • isDragging:标记是否正在拖动。
      • startXstartY:鼠标按下时的初始位置。
      • offsetXoffsetY:元素相对于初始位置的偏移量。
    • mounted 生命周期钩子:
      • 通过 this.$refs.draggable 获取元素引用。
      • handleMouseDown:鼠标按下时记录初始位置并标记为正在拖动。
      • handleMouseMove:鼠标移动时计算偏移量并更新元素的 transform 属性,使用 translate3d 实现平移。
      • handleMouseUp:鼠标松开时标记为停止拖动。
      • 添加事件监听器:为可拖动元素添加 mousedown 事件监听器,为文档添加 mousemovemouseup 事件监听器。
      • this.$once('hook:beforeDestroy',...):在组件销毁前移除事件监听器,防止内存泄漏。

使用示例

<template><div id="app"><DraggableComponent><h1>可拖动的组件</h1><p>这是另一种实现可拖动模块的方式,可以与其他组件组合使用。</p><AnotherComponent></AnotherComponent></DraggableComponent></div>
</template><script>javascript">
import DraggableComponent from './DraggableComponent.vue';
import AnotherComponent from './AnotherComponent.vue';export default {name: 'App',components: {DraggableComponent,AnotherComponent}
};
</script>

第三种方法:使用 Vue 3 的 Composition API 和 onMountedonUnmounted
如果你使用 Vue 3,还可以使用 Composition API 来实现:

<template><div ref="draggable" class="draggable-component"><slot></slot></div>
</template><script>javascript">
import { ref, onMounted, onUnmounted } from 'vue';export default {name: 'DraggableComponent',setup() {const draggable = ref(null);let isDragging = ref(false);let startX = ref(0);let startY = ref(0);let offsetX = ref(0);let offsetY = ref(0);const handleMouseDown = (e) => {isDragging.value = true;startX.value = e.clientX - offsetX.value;startY.value = e.clientY - offsetY.value;};const handleMouseMove = (e) => {if (isDragging.value) {offsetX.value = e.clientX - startX.value;offsetY.value = e.clientY - startY.value;draggable.value.style.transform = `translate3d(${offsetX.value}px, ${offsetY.value}px, 0)`;}};const handleMouseUp = () => {isDragging.value = false;};onMounted(() => {if (draggable.value) {draggable.value.addEventListener('mousedown', handleMouseDown);document.addEventListener('mousemove', handleMouseMove);document.addEventListener('mouseup', handleMouseUp);}});onUnmounted(() => {if (draggable.value) {draggable.value.removeEventListener('mousedown', handleMouseDown);document.removeEventListener('mousemove', handleMouseMove);document.removeEventListener('mouseup', handleMouseUp);}});return {draggable};}
};
</script><style scoped>
.draggable-component {position: absolute;background-color: #f0f0f0;border: 1px solid #ccc;padding: 10px;cursor: move;
}
</style>

代码解释

  • 模板部分
    • 与之前类似,使用 ref 获取元素引用。
  • 脚本部分
    • 使用 ref 来创建响应式变量:draggable 用于存储元素引用,isDraggingstartXstartYoffsetXoffsetY 存储拖动状态。
    • handleMouseDownhandleMouseMovehandleMouseUp 函数处理鼠标事件。
    • onMounted 钩子添加事件监听器。
    • onUnmounted 钩子移除事件监听器。

这些方法都可以实现可拖动模块,你可以根据自己的喜好和项目使用的 Vue 版本选择合适的实现方式。如果你需要更复杂的拖动功能,例如拖动排序、拖动边界限制、与其他组件交互等,可能需要进一步扩展上述代码或使用第三方库,如 vue-draggablevue-draggable-resizable

你可以将上述代码复制到相应的 Vue 文件中进行测试和使用,根据自己的需求进行修改和扩展。如果还有其他需求,例如限制拖动范围或添加更多的交互功能,可以进一步细化上述代码或向我提出更具体的问题。


http://www.ppmy.cn/server/159506.html

相关文章

前端小知识 鼠标穿透 pointer-events: none;

为什么会说到这个呢&#xff1f;是我觉得没有识别出来&#xff0c;然后就导致了这样的问题&#xff0c;这种情况不应该发生。我写了如下这样一段代码&#xff0c;但是发现当自己选择时间的时候无法选择。然后就发现变成了光标在闪烁。这样其实就是因为我选择到了这个input框的鼠…

STM32--定时器输出pwm知识点_stm32 pwm-CSDN博客

1. 选择TIM_OCMode_Toggle电平翻转模式&#xff0c; TIM_TimeBaseInitStruct.TIM_Period PWM_1_TIM_Period; 要设置成PWM_1_TIM_Period设置成0xffff - 1&#xff0c;设置成其他数值会出现脉冲一会有一会咩有。 资料&#xff1a;一文搞懂STM32定时器翻转模式&#xff08;产生…

SQL Server 导入Excel数据

1、选中指定要导入到哪个数据库&#xff0c;右键选择 》任务 》导入数据 2、数据源 选择Excel&#xff0c;点击 下一步(Next) 3、目前 选择OLE DB Provider &#xff0c;点击 下一步&#xff08;Next&#xff09; 4、默认 &#xff0c;点击 下一步&#xff08;Next&#xff09;…

JAVA-Exploit编写(3)--httpcomponents库使用文件上传

目录 1.依赖安装 2. upload文件代码 3.文件上传代码 1.依赖安装 文件上传处需要使用httpcomponents库,需要在Maven的pom.xml文件中导入依赖 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId>&l…

用LLM做测试驱动开发:有趣又高效的尝试

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

基于 Python 的毕设选题管理系统设计与实现

标题:基于 Python 的毕设选题管理系统设计与实现 内容:1.摘要 本文介绍了一个基于 Python 的毕设选题管理系统的设计与实现。该系统旨在解决传统毕设选题管理方式中存在的效率低下、信息不透明等问题。通过使用 Python 语言和相关技术&#xff0c;实现了对毕设选题的信息化管理…

2019-Android-高级面试题总结-从java语言到AIDL使用与原理

4.通过线程池 线程池的工作原理&#xff1a;线程池可以减少创建和销毁线程的次数&#xff0c;从而减少系统资源的消耗&#xff0c;当一个任务提交到线程池时 a. 首先判断核心线程池中的线程是否已经满了&#xff0c;如果没满&#xff0c;则创建一个核心线程执行任务&#xff0…

DATACOM-华为数通解决方案SDN、iMaster

华为数通解决方案 四大引擎华为数通解决方案园区网络WLAN数据中心广域承载SD-WAN 四大引擎 引擎设备举例举例设备介绍园区网络解决方案AirEngineAirEngine 5761S-11NetEngineNetEngine40E - X16A超宽 2T 单板&#xff1a;业界领先的超宽 2T 单板&#xff0c;可向 400G 端口、4T…