50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DoubleClickHeart(双击爱心)

📅 我们继续 50 个小项目挑战!------ DoubleClickHeart组件

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

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


使用 Vue 3 的 Composition API(<script setup>)结合 TailwindCSS 和 Font Awesome 创建一个双击点赞动画组件。用户可以双击图片区域触发一个"❤️ 爱心飞出"动画,并统计点赞次数。

这个交互体验非常适用于社交媒体、照片墙、内容点赞等场景。


🎯 组件目标

  • 用户双击图片区域时显示爱心动画
  • 显示当前点赞总次数
  • 动画结束后自动移除爱心元素
  • 使用 Vue 3 Composition API 管理状态
  • 使用 TailwindCSS 构建 UI 样式与布局
  • 支持动态定位和点击时间判断

⚙️ 技术实现点

技术点 描述
Vue 3 <script setup> 使用响应式变量管理点赞数、爱心列表
ref 响应式变量 控制 likeshearts 和 DOM 容器引用
双击检测逻辑 判断两次点击时间间隔是否小于 800ms
动态创建元素 在点击位置生成爱心图标并添加动画
TailwindCSS 样式 设置图片容器、文字样式、动画基础属性
自定义字体加载 使用 JS 动态加载 Oswald 字体与 Font Awesome 图标库
CSS 关键帧动画 实现放大淡出的爱心动画效果

🧱 组件实现

模板结构 <template>

html 复制代码
<template>
    <div class="flex min-h-screen flex-col items-center justify-center overflow-hidden font-[Oswald] text-white">
        <h3 class="mb-0 text-center">
            Double click on the image to
            <i class="fas fa-heart text-red-600"></i>
            it
        </h3>
        <small class="mb-5 block text-center">
            You liked it
            <span>{{ likes }}</span>
            times
        </small>

        <!-- 图片容器 -->
        <div
            class="relative h-[440px] w-[300px] cursor-pointer overflow-hidden bg-cover bg-center shadow-lg"
            :style="{ backgroundImage: `url(${imageUrl})` }"
            @click="handleClick"
            ref="container">
            <i
                v-for="heart in hearts"
                :key="heart.id"
                class="fas fa-heart heart-anim absolute text-red-600"
                :style="{ top: heart.y + 'px', left: heart.x + 'px' }"></i>
        </div>
    </div>
</template>

脚本逻辑 <script setup>

js 复制代码
<script setup>
import { onMounted, ref } from 'vue'

const likes = ref(0)
const hearts = ref([])
const container = ref(null)
let clickTime = 0

const handleClick = (e) => {
    const now = new Date().getTime()
    if (clickTime === 0) {
        clickTime = now
    } else {
        if (now - clickTime < 800) {
            createHeart(e)
            clickTime = 0
        } else {
            clickTime = now
        }
    }
}

const createHeart = (e) => {
    const rect = container.value.getBoundingClientRect()
    const xInside = e.clientX - rect.left
    const yInside = e.clientY - rect.top

    const id = Date.now()
    hearts.value.push({ id, x: xInside, y: yInside })
    likes.value++

    setTimeout(() => {
        hearts.value = hearts.value.filter((h) => h.id !== id)
    }, 1000)
}

const imageUrl =
    'https://images.unsplash.com/photo-1504215680853-026ed2a45def?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80'

onMounted(() => {
    const fontLink = document.createElement('link')
    fontLink.href = 'https://fonts.googleapis.com/css?family=Oswald'
    fontLink.rel = 'stylesheet'
    document.head.appendChild(fontLink)

    const faLink = document.createElement('link')
    faLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css'
    faLink.rel = 'stylesheet'
    faLink.crossOrigin = 'anonymous'
    document.head.appendChild(faLink)
})
</script>

样式部分 <style scoped>

css 复制代码
<style scoped>
.heart-anim {
    position: absolute;
    animation: grow 0.6s linear;
    transform: translate(-50%, -50%) scale(0);
}

@keyframes grow {
    to {
        transform: translate(-50%, -50%) scale(10);
        opacity: 0;
    }
}
</style>

🔍 重点效果实现

✅ 双击事件判断

通过记录点击时间戳来判断是否为双击行为:

js 复制代码
const now = new Date().getTime()
if (now - clickTime < 800) {
    createHeart(e)
    clickTime = 0
} else {
    clickTime = now
}

这是模拟原生 dblclick 事件的一种方式,同时保留了对单击行为的控制。

💡 动态生成爱心图标

每次双击会根据点击坐标生成一个爱心图标:

js 复制代码
hearts.value.push({ id, x: xInside, y: yInside })

并在一秒后自动从数组中移除,以实现动画结束后的清理。

🎨 动画设计

使用 CSS 关键帧实现放大并透明消失的效果:

css 复制代码
@keyframes grow {
    to {
        transform: translate(-50%, -50%) scale(10);
        opacity: 0;
    }
}

配合 Tailwind 的 absolute 定位,实现了视觉上"从点击点飞出"的效果。


🎨 TailwindCSS 样式重点讲解

类名 作用
min-h-screen, flex-col, items-center, justify-center 居中布局
font-[Oswald], text-white 字体与文字颜色
relative, absolute 心形图标的绝对定位
h-[440px] w-[300px] 固定图片容器大小
bg-cover bg-center 设置背景图片居中覆盖
cursor-pointer 鼠标悬停为手型
overflow-hidden 防止爱心动画溢出容器
shadow-lg 添加阴影提升层次感
text-red-600 爱心颜色设置为红色

这些类帮助我们快速构建了一个美观、互动性强的点赞组件。


📁 常量定义 + 组件路由

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

js 复制代码
{
        id: 29,
        title: 'Double Click Heart',
        image: 'https://50projects50days.com/img/projects-img/29-double-click-heart.png',
        link: 'DoubleClickHeart',
    },

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

js 复制代码
{
        path: '/DoubleClickHeart',
        name: 'DoubleClickHeart',
        component: () => import('@/projects/DoubleClickHeart.vue'),
    },

🏁 总结

基于 Vue 3 和 TailwindCSS 的双击点赞动画组件不仅实现了基本的交互功能,它非常适合用于社交平台、图片浏览、内容互动等需要增强用户体验的场景。

你可以进一步扩展此组件的功能包括:

  • ✅ 添加音效反馈(如"滴"一声)
  • ✅ 支持移动端触摸双击识别
  • ✅ 支持本地存储点赞数(使用 localStorage)
  • ✅ 添加粒子爆炸或其他动画效果
  • ✅ 将组件封装为 <DoubleHeartImage /> 可复用组件

👉 下一篇,我们将完成AutoTextEffect组件,一个类似打字机的组件,可以调节速度。🚀

感谢阅读,欢迎点赞、收藏和分享 😊

相关推荐
魔云连洲17 小时前
深入解析:Object.prototype.toString.call() 的工作原理与实战应用
前端·javascript·原型模式
JinSo17 小时前
alien-signals 系列 —— 认识下一代响应式框架
前端·javascript·github
开心不就得了17 小时前
Glup 和 Vite
前端·javascript
szial17 小时前
React 快速入门:菜谱应用实战教程
前端·react.js·前端框架
西洼工作室17 小时前
Vue CLI为何不显示webpack配置
前端·vue.js·webpack
黄智勇18 小时前
xlsx-handlebars 一个用于处理 XLSX 文件 Handlebars 模板的 Rust 库,支持多平台使
前端
brzhang19 小时前
为什么 OpenAI 不让 LLM 生成 UI?深度解析 OpenAI Apps SDK 背后的新一代交互范式
前端·后端·架构
brzhang20 小时前
OpenAI Apps SDK ,一个好的 App,不是让用户知道它该怎么用,而是让用户自然地知道自己在做什么。
前端·后端·架构
爱看书的小沐20 小时前
【小沐学WebGIS】基于Three.JS绘制飞行轨迹Flight Tracker(Three.JS/ vue / react / WebGL)
javascript·vue·webgl·three.js·航班·航迹·飞行轨迹
程序员王天20 小时前
【开发AGIC】Vue3+NestJS+DeepSeek AI作业批改系统(已开源)
vue.js·ai编程·nestjs