50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DragNDrop(拖拽占用组件)

📅 我们继续 50 个小项目挑战!—— DragNDrop组件

仓库地址:https://github.com/SunACong/50-vue-projects

项目预览地址:https://50-vue-projects.vercel.app/

在这里插入图片描述


使用 Vue 3 的 Composition API 和 <script setup> 语法结合 TailwindCSS 构建一个支持拖拽交互的图片拖放组件。该组件允许用户将一张图片从一个容器拖动并释放到另一个“空位”中,并带有视觉反馈(如悬停高亮、背景变化等)。

🎯 组件目标

  • 创建多个“空位”容器
  • 默认展示一张可拖动的图片
  • 支持拖拽交互并投放到任意空位
  • 投放后更新对应位置的图片状态
  • 拖拽过程中提供视觉反馈(如悬停样式)
  • 使用 TailwindCSS 快速构建现代 UI 界面

⚙️ 技术实现点

技术点描述
Vue 3 Composition API (<script setup>)使用响应式变量管理组件状态
ref 响应式变量控制当前图片所在索引与悬停状态
v-for 循环渲染动态生成多个容器
@dragstart, @dragend, @dragover, @drop 等事件实现完整的拖拽交互逻辑
TailwindCSS 条件类绑定根据状态动态应用样式
:style 动态绑定背景图展示图片资源

🧱 组件实现

模板结构 <template>

<template><div class="flex h-screen items-center justify-center overflow-hidden bg-sky-500"><!-- 多个空位容器 --><divv-for="(empty, index) in empties":key="index":class="['m-2 h-36 w-36 border-4 border-black bg-white',isHovered[index] && 'border-dashed border-black bg-gray-800',]"@dragover.prevent="dragOver"@dragenter.prevent="dragEnter(index)" @dragleave="dragLeave(index)"@drop="dragDrop(index)"><!-- 当前图片所在的容器 --><divv-if="index === filledIndex"class="h-full w-full cursor-pointer bg-cover":style="{ backgroundImage: `url(${imageUrls[index]})` }"draggable="true"@dragstart="dragStart"@dragend="dragEnd"></div></div></div>
</template>

脚本逻辑 <script setup>

<script setup>
import { ref } from 'vue'const filledIndex = ref(0)
const isHovered = ref(Array(5).fill(false))// 用于循环生成 5 个空位容器
const empties = Array.from({ length: 5 }, (_, index) => index)// 图片地址数组
const imageUrls = ['https://picsum.photos/id/10/150/150','https://picsum.photos/id/11/150/150','https://picsum.photos/id/12/150/150','https://picsum.photos/id/13/150/150','https://picsum.photos/id/14/150/150',
]// 拖拽开始
const dragStart = () => {// 可添加 hold 效果或数据存储
}// 拖拽结束
const dragEnd = () => {// 可添加恢复效果
}// 鼠标悬停时触发
const dragOver = () => {}// 进入容器时触发
const dragEnter = (index) => {isHovered.value[index] = true
}// 离开容器时触发
const dragLeave = (index) => {isHovered.value[index] = false
}// 投放操作
const dragDrop = (index) => {filledIndex.value = indexisHovered.value = Array(5).fill(false)
}
</script>

自定义样式 <style scoped>

<style scoped>
[draggable='true'] {transition: all 0.2s ease;
}
</style>

🔍 重点效果实现

✅ 拖拽交互逻辑详解

1. 拖拽开始:dragStart

当用户点击并开始拖动图片时,会触发 dragStart 方法。你可以在这里做一些准备操作,例如记录当前拖动的数据。

2. 拖拽进入容器:dragEnter(index)

当鼠标带着元素进入某个容器时,我们通过传入 index 设置该容器的悬停状态为 true,从而激活其高亮样式。

3. 拖拽离开容器:dragLeave(index)

当鼠标离开容器时,设置该容器的悬停状态为 false,恢复默认样式。

4. 投放完成:dragDrop(index)

这是整个拖拽流程的核心,它负责更新 filledIndex,将图片移动到新的容器,并重置所有悬停状态。


💡 视觉反馈机制

我们使用了一个布尔数组 isHovered 来保存每个容器是否被悬停:

const isHovered = ref(Array(5).fill(false))

并通过 v-if="index === filledIndex" 判断哪个容器应该显示图片,其他则为空白容器。

TailwindCSS 中根据这个状态来切换样式:

:class="['m-2 h-36 w-36 border-4 border-black bg-white',isHovered[index] && 'border-dashed border-black bg-gray-800',
]"

🖼️ 图片动态加载

使用了 :style 来动态设置背景图:

:style="{ backgroundImage: `url(${imageUrls[index]})` }"

每张图片都来自 Picsum Photos 提供的随机图片服务,确保每次运行都能看到不同的内容。


🎨 TailwindCSS 样式重点讲解

类名作用
h-screen, items-center, justify-center全屏高度 + 内容居中布局
overflow-hidden防止内容溢出
bg-sky-500设置背景颜色为浅蓝色
h-36, w-36设置每个容器的宽高为 36(9rem)
m-2设置外边距为 2(0.5rem)
border-4, border-black黑色边框
bg-white / bg-gray-800默认和悬停状态下的背景颜色
border-dashed悬停时边框变为虚线
cursor-pointer设置图片区域为可点击
bg-cover图片背景自适应填充
transition添加拖拽过程中的平滑过渡动画

📁 常量定义 + 组件路由

constants/index.js 添加组件预览常量:

{id: 21,title: 'Drag N Drop',image: 'https://50projects50days.com/img/projects-img/21-drag-n-drop.png',link: 'DragNDrop',},

router/index.js 中添加路由选项:

{path: '/DragNDrop',name: 'DragNDrop',component: () => import('@/projects/DragNDrop.vue'),},

📁 扩展功能建议

进一步扩展的功能推荐:

  • ✅ 支持多张图片同时拖动
  • ✅ 支持图片预览拖拽(不立即改变原图位置)
  • ✅ 拖拽时高亮目标容器边界
  • ✅ 支持触摸设备拖拽交互(移动端适配)
  • ✅ 封装为可复用组件(支持 props 传入图片列表)

🏁 总结

👉 下一篇,我们将完成DrawApp组件,创建一个画板具有调节画笔粗细的功能,并且能够一键清除画板上的内容。🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87272.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot应用即使使用了连接池,MySQL数据库仍然有大量sleep状态的连接

springboot应用即使使用了连接池&#xff0c;MySQL数据库仍然有大量sleep状态的连接 问题背景概念理解MySQL配置参数wait_timeout概念Hikari配置参数&#xff08;项目使用hikari作为数据库连接池&#xff09; 实践出真知总结和解决思路 问题背景 近期客户生产环境报&#xff1…

windows下安装和使用git

本文为windows下git的下载安装和使用。 git下载和安装 参考&#xff1a; windows安装git&#xff08;全网最详细&#xff0c;保姆教程&#xff09;-CSDN博客 【学了就忘】Git介绍 — 4.Git的安装 - 简书 先解决下载时的一些疑惑&#xff1a; 选择哪个架构&#xff1f; 电脑ARM6…

借助工具给外语视频加双语字幕的实用指南​

给外语视频配上双语字幕&#xff0c;能让不同语言背景的观众更轻松理解内容&#xff0c;也能让视频在传播时更受欢迎。现在有不少智能工具能帮我们高效完成这项工作&#xff0c;比如 ViiTor AI 平台&#xff0c;它在处理双语字幕方面有不少实用功能&#xff0c;下面就结合其功能…

Claude 4 与 Gemini 2.5 Pro:开发者深度比较

Claude 4 与 Gemini 2.5 Pro&#xff1a;开发者深度比较 在使用相同的编码挑战对Claude Sonnet 4和Gemini 2.5 Pro Preview进行广泛的正面测试后&#xff0c;我发现了每个开发人员都应该了解的显著性能差异。我的发现揭示了执行速度、成本效率以及最重要的&#xff0c;精确执行…

怎么进入9870端口

在实验时想进入9870端口查看safe状态 但是输入localhost:9870后显示&#xff1a; 首先使用jps确认hadoop状态&#xff1a; 从 jps 的输出来看&#xff0c;Hadoop 的核心服务&#xff08;NameNode、DataNode、ResourceManager、NodeManager 等&#xff09;都已经正常运行&…

Windows、Linux、macOS 三大系统安装 Git 的常见坑点及解决方案,附带 具体操作示例,帮助新手快速避坑

以下是 Windows、Linux、macOS 三大系统安装 Git 的常见坑点及解决方案,附带 具体操作示例,帮助新手快速避坑。 一、Windows 系统安装 Git 1. 安装路径含空格或中文 坑点:默认路径 C:\Program Files\Git 可能导致某些脚本报错。 解决:自定义路径(如 D:\DevTools\Git)。…

OpenAI最新 GPT-4.1 、 GPT-4.1 mini 和 GPT-4.1 nano 新模型如何在ChatGPT付费创作系统平台对接API使用

GPT-4.1 ‌是 OpenAI 于2025年4月15日发布的最新语言模型系列&#xff0c;包括 GPT-4.1 、 GPT-4.1 mini 和 GPT-4.1 nano 三款新成员。这些模型在编程、指令遵循和长上下文理解方面表现出色&#xff0c;支持最大可达100万个Token的上下文窗口&#xff0c;适用于处理复杂任务和…

计算机网络(三)传输层TCP

目录 一、TCP概述​ 二、TCP三大核心特性 三、 对比UDP​​ &#xff08;1&#xff09;TCP、UDP对比 &#xff08;2&#xff09;TCP、UDP头部格式: &#xff08;3&#xff09;应用场景 ​ 四、TCP的三次握手、四次挥手 &#xff08;1&#xff09;三次握手&#xff08;建…

Spring、SpringBoot 本身为什么不提供 Bean 的异步初始化

这是一个很有深度的架构问题&#xff01;Spring/Spring Boot 本身为什么不直接提供 Bean 的异步初始化&#xff1f; 下面从原理、历史、设计哲学、技术挑战、社区现状等多个层面为你详细分析。 一、Spring Bean 初始化的默认行为 Spring IoC 容器在启动时&#xff0c;会同步地…

第十三节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - 接口操作审计日志功能

Vben5 系列文章目录 💻 基础篇 ✅ 第一节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 ✅ 第二节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Python Flask 后端开发详解(附源码) ✅ 第三节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入…

AI掌柜失守记:AI Agent商业自动化边界实验

1. 实验设计&#xff1a;数字掌柜接管实体货架 1.1 硬件载体与虚拟人格构建 位于旧金山的实验场地被改造成微型零售生态系统&#xff1a;智能冰箱搭配商品篮构成实体货架&#xff0c;iPad自助结账系统连接Venmo支付接口&#xff0c;Slack通讯平台成为人机交互窗口。Claude So…

NAT 打洞

本文基于NAT3NAT3实现upd打洞&#xff08;假设你对NAT类型已经很清楚&#xff09; 如果A网络的NATAB网络的NATB的值大于6则打洞会失败&#xff0c;需要使用turn中继服务 STUN协议解析 #pragma once #include "hv/UdpClient.h" #include "fmt/format.h" /*…

java近期工作总结

近期工作中的一些总结 &#xff08;1&#xff09;三层模板和流程 我发现很多东西其实吧&#xff0c;三层就是一个模板和流程&#xff1b; 正向推&#xff0c;从控制层开始&#xff0c;反向从内个sql开始写&#xff0c;大部分应该就是从xml文件开始的&#xff0c;然后写到控制层…

vue中的torefs

在 Vue 中&#xff0c; toRefs(state) 的返回值是一个 新对象&#xff0c;其中每个属性都是对应 state 中原始属性的 ref 对象。具体来说&#xff1a; 返回值的结构与特性 1. 对象结构 - 若输入 state 为 { a: 1, b: text } &#xff0c;则 toRefs(state) 返回&a…

可编程逻辑器件的演进与对比分析

可编程逻辑器件的演进与对比分析 目录 离散逻辑芯片与早期PLD的限制CPLD的诞生与结构特点FPGA的架构创新CPLD与FPGA的核心差异总结 1. 离散逻辑芯片与早期PLD的限制 在还没有发明出可编程逻辑器件&#xff08;PLD: Programmable Logic Device&#xff09;之前&#xff0c;设…

Ubuntu机器开启root用户远程登录

一般正常情况是可以直接使用非root用户登录&#xff0c;但是由于权限问题&#xff0c;所以部分内容需要远程ROOT用户登录&#xff0c;具体如下&#xff1a; 1️⃣配置root用户密码 一般情况下系统中root不能直接登录&#xff0c;所以也没有保存root密码&#xff0c;现在需要登…

rockchip android14 设置不休眠

rockchip android14 设置不休眠 文章目录 rockchip android14 设置不休眠前言一、代码路径二、代码修改前言 在rk 的android14代码中设置开机后永不休眠 一、代码路径 device/rockchip/common/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml二、…

什么是数据孤岛?如何解决数据孤岛问题?

目录 一、数据孤岛的定义与表现 1. 数据孤岛的定义 2. 数据孤岛的表现形式 二、数据孤岛产生的原因 1. 技术层面 2. 组织管理层面 3. 业务流程层面 三、数据孤岛带来的危害 1. 对企业决策的影响 2. 对业务运营效率的影响 3. 对数据治理和安全的影响 四、解决数据孤…

自定义Cereal XML输出容器节点

自定义Cereal XML输出容器节点 CEREAL_SERIALIZE_INTRUSIVE 在 1.优化Cereal宏 一行声明序列化函数 QString、QVector、QList、QMap序列化在2.在Cereal中支持Qt容器序列化 静态成员函数type_node检测在 3.利用SFINAE检测成员函数 &#x1f680; 告别value0&#xff1a;自定义Ce…

Spark 写入hive表解析

FileOutputCommitter中提交mapreduce.fileoutputcommitter.algorithm.version有v1和v2两个版本。 v1版本Spark写入文件的流程&#xff1a; 1.当task完成的时候&#xff0c;会将task的结果文件先写入到临时目录下面。 2.所有的task完成后&#xff0c;将所有的结果文件写入到结…