线上版本,带滑动至顶部

This commit is contained in:
WindowBird 2025-11-19 08:51:25 +08:00
parent 018cd2d099
commit 96dca18131
5 changed files with 52 additions and 100 deletions

View File

@ -1,9 +1,10 @@
<template> <template>
<UApp> <UApp>
<NuxtLayout> <NuxtLayout>
<NuxtPage /> <NuxtPage/>
</NuxtLayout> </NuxtLayout>
<ScrollToTop/>
</UApp> </UApp>
</template> </template>
<script setup lang="ts"> <script lang="ts" setup>
</script> </script>

View File

@ -1,18 +1,14 @@
<script lang="ts" setup> <script lang="ts" setup>
const contacts = [ const contacts = [
{ {
label: '电话', label: '电话',
value: '15280659990', value: '15280659990',
icon: 'i-heroicons-phone', icon: 'i-heroicons-phone',
}, },
{ {
label: '邮箱', label: '邮箱',
value: '564737095@qq.com', value: '564737095@qq.com',
icon: 'i-heroicons-envelope', icon: 'i-heroicons-envelope',
}, },
{ {
label: '地址', label: '地址',

View File

@ -4,7 +4,7 @@
<UPopover mode="hover"> <UPopover mode="hover">
<UButton <UButton
class="bg-green-500 hover:bg-green-600 text-white px-4 py-3 rounded-l-lg shadow-lg transition-all duration-300" class="bg-primary hover:bg-primary-600 text-white px-4 py-3 rounded-l-lg shadow-lg transition-all duration-300"
color="neutral" label="联系客服" color="neutral" label="联系客服"
variant="subtle"/> variant="subtle"/>
<template #content> <template #content>

View File

@ -1,106 +1,60 @@
<!-- components/ScrollToTop.vue -->
<template> <template>
<UButton <!-- 悬浮置顶按钮 -->
v-show="isVisible" <Transition name="fade-slide">
:aria-label="ariaLabel" <button
:class="buttonClasses" v-show="showScrollToTop"
aria-label="回到顶部"
:icon="icon" class="fixed bottom-32 right-8 z-50 rounded-full p-3 shadow-lg transition-all duration-300 focus:outline-none
bg-primary/90 backdrop-blur-md border border-white/20
:variant="variant" hover:bg-primary/95 hover:-translate-y-0.5 hover:scale-110 hover:shadow-xl
@click="handleClick" active:scale-95 focus:ring-4 focus:ring-primary/30
@mouseenter="isHovered = true" "
@mouseleave="isHovered = false" title="回到顶部"
@click="scrollToTop"
> >
<!-- 插槽支持自定义内容 --> <UIcon class="w-6 h-6 text-white -rotate-45" name="i-lucide-rocket"/>
<slot> </button>
<span v-if="showText && isHovered" class="ml-2 text-xs font-medium"> </Transition>
{{ text }}
</span>
</slot>
</UButton>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
//
const showScrollToTop = ref(false)
interface Props { //
threshold?: number
position?: 'br' | 'bl' | 'tr' | 'tl' // bottom-right, bottom-left, etc.
size?: 'sm' | 'md' | 'lg'
color?: 'primary' | 'green' | 'blue' | 'gray'
variant?: 'solid' | 'outline' | 'soft'
icon?: string
showText?: boolean
text?: string
ariaLabel?: string
smoothScroll?: boolean
}
const props = withDefaults(defineProps<Props>(), {
threshold: 300,
position: 'br',
size: 'lg',
color: 'green',
variant: 'solid',
icon: 'i-heroicons-arrow-up',
showText: false,
text: '回到顶部',
ariaLabel: '回到页面顶部',
smoothScroll: true
})
const isVisible = ref(false)
const isHovered = ref(false)
//
const positionClasses = computed(() => {
const map = {
br: 'bottom-6 right-6',
bl: 'bottom-6 left-6',
tr: 'top-6 right-6',
tl: 'top-6 left-6'
}
return map[props.position] || map.br
})
//
const buttonClasses = computed(() => [
'fixed z-50 rounded-full transition-all duration-300 ease-in-out',
positionClasses.value,
{
'opacity-100': isVisible.value,
'opacity-0': !isVisible.value,
'hover:scale-110': isVisible.value,
'px-4': props.showText && isHovered.value
}
])
const handleScroll = () => { const handleScroll = () => {
isVisible.value = window.scrollY > props.threshold showScrollToTop.value = window.scrollY > 300
} }
const handleClick = () => { //
if (props.smoothScroll) { const scrollToTop = () => {
window.scrollTo({top: 0, behavior: 'smooth'}) window.scrollTo({
} else { top: 0,
window.scrollTo(0, 0) behavior: 'smooth'
} })
//
emit('click')
} }
const emit = defineEmits<{ //
click: []
}>()
onMounted(() => { onMounted(() => {
window.addEventListener('scroll', handleScroll, {passive: true}) window.addEventListener('scroll', handleScroll)
}) })
//
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('scroll', handleScroll) window.removeEventListener('scroll', handleScroll)
}) })
</script> </script>
<style scoped>
/* 保留过渡动画 */
.fade-slide-enter-active,
.fade-slide-leave-active {
transition: all 0.3s ease;
}
.fade-slide-enter-from,
.fade-slide-leave-to {
opacity: 0;
transform: translateY(10px);
}
</style>

View File

@ -6,7 +6,8 @@
// API基础地址配置 // API基础地址配置
export const API_CONFIG = { export const API_CONFIG = {
// 开发环境API地址 // 开发环境API地址
BASE_URL: 'http://192.168.1.4:4101', // BASE_URL: 'http://192.168.1.4:4101',
BASE_URL: 'https://ele.ccttiot.com/prod-api',
// API端点配置 // API端点配置
ENDPOINTS: { ENDPOINTS: {