motion-knowledge and ContactFloatingButton optimize

This commit is contained in:
WindowBird 2025-10-27 13:39:43 +08:00
parent 58b3e14e8e
commit a27e168865
4 changed files with 22 additions and 106 deletions

View File

@ -1,97 +1,22 @@
<!-- components/ContactFloatingButton.vue --> <!-- components/ContactFloatingButton.vue -->
<template> <template>
<div class="fixed right-6 top-1/2 transform -translate-y-1/2 z-50 flex items-center"> <div class="fixed right-6 top-1/2 transform -translate-y-1/2 z-50 flex items-center">
<!-- 二维码面板 --> <UPopover mode="hover">
<Transition name="fade-slide"> <UButton
<div v-if="showQR" class="w-64 overflow-hidden transition-all duration-300 ease-out;">
<img
:alt="qrAltText"
:src="qrImage"
class="w-full h-auto border-4 border-white rounded-lg shadow-xl"
>
</div>
</Transition>
<!-- 客服按钮 --> class="bg-green-500 hover:bg-green-600 text-white px-4 py-3 rounded-l-lg shadow-lg transition-all duration-300"
<button color="neutral" label="联系客服"
:class="{ 'ml-2': showQR }" variant="subtle"/>
class="bg-green-500 hover:bg-green-600 text-white px-4 py-3 rounded-l-lg shadow-lg transition-all duration-300" <template #content>
@click="onButtonClick" <div class="w-64 overflow-hidden transition-all duration-300 ease-out;">
@mouseenter="showQR = true" <img
@mouseleave="onMouseLeave" alt="QRCode"
> class="w-full h-auto border-4 border-white rounded-lg shadow-xl"
<span class="button-text">{{ buttonText }}</span> src="/img/QRCode.png"
</button> >
</div>
</template>
</UPopover>
</div> </div>
</template> </template>
<script setup>
import {ref} from 'vue'
const props = defineProps({
qrImage: {
type: String,
default: '/img/img.png'
},
qrAltText: {
type: String,
default: '客服二维码'
},
buttonText: {
type: String,
default: '联系客服'
},
hoverDelay: {
type: Number,
default: 300 // (ms)
}
})
const emit = defineEmits(['click'])
const showQR = ref(false)
let hideTimer = null
const onMouseLeave = () => {
hideTimer = setTimeout(() => {
showQR.value = false
}, props.hoverDelay)
}
const cancelHide = () => {
if (hideTimer) {
clearTimeout(hideTimer)
hideTimer = null
}
}
const onButtonClick = () => {
emit('click')
//
cancelHide()
showQR.value = true
}
</script>
<style scoped>
/* 按钮样式 */
.writing-mode-vertical {
writing-mode: vertical-rl;
text-orientation: mixed;
}
/* 动画效果 */
.fade-slide-enter-active,
.fade-slide-leave-active {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.fade-slide-enter-from,
.fade-slide-leave-to {
opacity: 0;
transform: translateX(10px);
}
</style>

View File

@ -93,22 +93,13 @@ const cardItems = ref([
class="shadow-lg hover:shadow-2xl transition-shadow duration-300 h-full" class="shadow-lg hover:shadow-2xl transition-shadow duration-300 h-full"
reverse reverse
> >
<Motion
:initial="{ scale: 0.9, opacity: 0.7 }" <img
:transition="{ duration: 0.4, delay: 0.2 + 0.1 * index }" :src="item.image"
:while-hover="{ alt="Illustration"
scale: 1.1, class="w-full shadow-2xl rounded-2xl"
rotate: 2,
transition: { duration: 0.3 }
}"
:while-in-view="{ scale: 1, opacity: 1 }"
> >
<img
:src="item.image"
alt="Illustration"
class="w-full shadow-2xl rounded-2xl"
>
</Motion>
</UPageCTA> </UPageCTA>
</Motion> </Motion>
</view> </view>
@ -120,7 +111,7 @@ const cardItems = ref([
:transition="{ :transition="{
duration: 0.8, duration: 0.8,
delay: 0.3, delay: 0.3,
type: 'spring',
stiffness: 100, stiffness: 100,
damping: 15 damping: 15
}" }"

BIN
public/img/QRCode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB