Files
2026-07-10 18:23:41 +08:00

133 lines
4.0 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
import { testimonials as defaultTestimonials } from "~/data/home";
const props = defineProps({
testimonials: {
type: Array,
default: () => defaultTestimonials,
},
routes: {
type: Array,
default: () => [],
},
sectionId: {
type: String,
default: "testimonials",
},
});
const currentIndex = ref(0);
const isPaused = ref(false);
let timer;
const current = computed(() => props.testimonials[currentIndex.value]);
const goToSlide = (index) => {
currentIndex.value = index;
};
const goToPrev = () => {
currentIndex.value =
currentIndex.value === 0 ? props.testimonials.length - 1 : currentIndex.value - 1;
};
const goToNext = () => {
currentIndex.value =
currentIndex.value === props.testimonials.length - 1 ? 0 : currentIndex.value + 1;
};
const startAutoplay = () => {
timer = window.setInterval(() => {
if (!isPaused.value) {
goToNext();
}
}, 5000);
};
onMounted(() => {
startAutoplay();
});
onBeforeUnmount(() => {
window.clearInterval(timer);
});
</script>
<template>
<section
:id="sectionId"
class="bg-white py-20"
@mouseenter="isPaused = true"
@mouseleave="isPaused = false"
>
<div class="container-gm">
<div class="flex flex-col gap-5 md:flex-row md:items-end md:justify-between" data-reveal>
<div class="max-w-3xl">
<p class="text-sm uppercase tracking-[0.3em] text-[#a1a1a1]">Voice</p>
<h2 class="section-title mt-4">客户真实评价见证服务品质</h2>
<p class="mt-3 text-[#777]">
从真实客户视角补充信任背书进一步强化团队专业度和落地能力
</p>
</div>
<SectionRouteLinks :routes="routes" />
</div>
<div class="mx-auto mt-12 max-w-3xl text-center" data-reveal>
<div class="mx-auto flex h-16 w-16 items-center justify-center rounded-lg bg-gm-light text-xl font-semibold text-gm-green">
{{ current?.name.slice(0, 1) }}
</div>
<transition
mode="out-in"
enter-active-class="transition duration-500 ease-out"
enter-from-class="translate-y-3 opacity-0"
enter-to-class="translate-y-0 opacity-100"
leave-active-class="transition duration-300 ease-in"
leave-from-class="translate-y-0 opacity-100"
leave-to-class="-translate-y-2 opacity-0"
>
<div :key="current.id" class="mt-6">
<blockquote class="text-balance text-lg italic leading-8 text-[#555] md:text-xl">
{{ current.quote }}
</blockquote>
<p class="mt-6 text-base font-semibold text-[#262626]">{{ current.name }}</p>
<p class="text-sm text-[#9b9b9b]">{{ current.title }}</p>
</div>
</transition>
</div>
<div class="mt-8 flex items-center justify-center gap-2">
<button
v-for="(item, index) in props.testimonials"
:key="item.id"
type="button"
:aria-label="`切换到第 ${index + 1} 条评价`"
class="size-3 rounded-full transition-all duration-300"
:class="index === currentIndex ? 'bg-gm-green' : 'bg-gray-300'"
@click="goToSlide(index)"
/>
</div>
<div class="mt-6 flex items-center justify-center gap-4">
<button
type="button"
class="flex size-10 items-center justify-center rounded-full border border-gm-border text-[#666] transition hover:border-gm-green hover:text-gm-green"
aria-label="上一条评价"
@click="goToPrev"
>
</button>
<button
type="button"
class="flex size-10 items-center justify-center rounded-full border border-gm-border text-[#666] transition hover:border-gm-green hover:text-gm-green"
aria-label="下一条评价"
@click="goToNext"
>
</button>
</div>
</div>
</section>
</template>