【Tailwind + Vue3】100行代码手写一个客服组件

【Tailwind + Vue3】100行代码手写一个客服组件

通常在官网页面上,都会有一个在右下角的客服小组件,有几个按钮,显示电话,微信等信息:
在这里插入图片描述
主要有以下几个难点:

  1. 动态类名绑定: 在迭代生成的每个工具项上,使用 :class 绑定来动态添加特定的圆角样式,这取决于元素在数组中的位置(是否为第一个或最后一个元素),实现这一点需要理解 Vue 的动态类名绑定和 JavaScript 的逻辑表达式。

  2. 鼠标悬停动态效果: 实现鼠标悬停时显示详细信息的逻辑较为复杂,需要理解如何根据鼠标事件(mouseenter 和 mouseleave)动态更新 hoveredItemId 的状态,并据此条件渲染对应的详情框,同时应用 CSS 动画。

  3. Vue.js 事件处理: 代码中通过为 @mousedown 和 @touchstart 事件绑定处理函数来预设拖拽开始的逻辑(尽管示例中没有具体实现拖拽逻辑),这涉及到了对 Vue.js 事件监听和处理的理解。

  4. CSS 动画与 Tailwind CSS 的结合使用: 通过使用类似 animate-fadeIn 的类,展示了如何在 Vue 组件中使用 Tailwind CSS 实现简单的动画效果。理解如何在 Tailwind CSS 中扩展动画或直接在样式表中定义动画是实现这一点的关键。

  5. 条件渲染和动画: 使用 v-for 指令遍历 items 数组生成每个工具项,v-if 条件渲染显示额外信息(如电话号码或二维码)。

全部代码

<template>
    <div class="cursor-pointer fixed bottom-16 right-4 z-10" @mousedown="handleDragStart" @touchstart="handleDragStart">
        <div class="mb-8 -mr-2">
            <img src="../../assets/floatBar/avatar.svg" alt="avatar"
                class="border-blue-500 border rounded-full ml-1 bg-white">
            <img src="../../assets/floatBar/Wechat.svg" alt="wechat">
        </div>
        <!-- 项始终显示在页面右下角,为整个容器添加圆角 -->
        <div class="pt-2 ml-1">
            <div class="relative flex flex-col items-end rounded-2xl shadow-lg">
                <!-- In your template, update the div that iterates over items -->
                <div v-for="(item,index) in items" :key="item.id" :class="{'rounded-btn-first': index == 0, 'rounded-btn-last': index == items.length - 1}"
                    class="flex flex-col items-center bg-white p-2 cursor-pointer relative last:mb-0 hover:bg-gray-50 last:rounded-btn-last"
                    @mouseenter="handleMouseEnter(item)" @mouseleave="handleMouseLeave">
                    <!-- hover items -->
                    <div v-if="hoveredItemId === item.id && item.detail"
                        class="absolute -left-2 transform -translate-x-full bg-white p-2 shadow-lg text-sm rounded-lg animate-fadeIn">
                        <div class="flex mx-1">
                            <img :src="item.icon" alt="" class="w-4 h-4 mt-0.5" v-if="index!=3">
                            <span class="mr-4 ml-2" v-if="index!=3">{
    
    {
    
     item.detail }}</span>
                            <img :src="item.detail" alt="qrcode" v-if="index==3" class="">
                        </div>
                    </div>
                    <img :src="item.icon" alt="" class="w-6 h-6">
                    <span class="text-[12px] text-center text-[#4E5F78] ">{
    
    {
    
     item.text }}</span>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import {
    
     ref } from 'vue';
import onlineServiceIcon from '../../assets/floatBar/online service.svg'
import demonIcon from '../../assets/floatBar/demonstration.svg'
import phoneIcon from '../../assets/floatBar/phone.svg'
import learnMoreIcon from '../../assets/floatBar/learn more.svg'
import qrcode from '../../assets/floatBar/qrcode.jpg'

const items = ref([
    {
    
     id: 1, text: '在线咨询', detail: 'xxx', icon: onlineServiceIcon },
    {
    
     id: 2, text: '预约演示', detail: 'xxx', icon: demonIcon },
    {
    
     id: 3, text: '电话咨询', detail: 'xxx', icon: phoneIcon },
    {
    
     id: 4, text: '了解更多', detail: qrcode, icon: learnMoreIcon }
]);

const hoveredItemId = ref(null); // Track the hovered item

const handleMouseEnter = (item) => {
    
    
    hoveredItemId.value = item.id; // Set the hovered item ID
};

const handleMouseLeave = () => {
    
    
    hoveredItemId.value = null; // Clear the hovered item ID on mouse leave
};
</script>

<style scoped>
.detail-box {
    
    
    position: absolute;
    top: 50%;
    left: 0; /* Adjusted for demonstration */
    transform: translateX(-100%) translateY(-50%);
    white-space: nowrap;
    background-color: #fff;
    border: 1px solid #ddd;
    padding: 8px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.rounded-btn-first {
    
    
    border-radius: 10px 10px 0 0;
}

.rounded-btn-last {
    
    
    border-radius: 0 0 10px 10px;
}
</style>

效果展示

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_56699208/article/details/136657689