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组件,一个类似打字机的组件,可以调节速度。🚀

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

相关推荐
2301_796512523 分钟前
使用状态管理、持久化存储或者利用现有的库来辅助React Native鸿蒙跨平台开发开发一个允许用户撤销删除的操作
javascript·react native·react.js
全马必破三7 分钟前
浏览器原理知识点总结
前端·浏览器
零Suger9 分钟前
React 组件通信
前端·react.js·前端框架
LYFlied12 分钟前
【每日算法】 LeetCode 394. 字符串解码
前端·数据结构·算法·leetcode·面试·职场和发展
前端不太难19 分钟前
RN Navigation vs Vue Router 的架构对比
javascript·vue.js·架构
硕子鸽22 分钟前
UniApp + Dify 实战:详解 SSE 流式响应的解析与前端渲染
前端·uni-app·dify
lxh011323 分钟前
复原IP地址
前端·数据结构·算法
小白学大数据24 分钟前
Python 爬虫如何分析并模拟 JS 动态请求
开发语言·javascript·爬虫·python
2301_7965125224 分钟前
React Native鸿蒙跨平台开发包含输入收入金额、选择收入类别、记录备注和日期等功能,实战react-native-paper组件
javascript·react native·react.js