初始化

This commit is contained in:
2026-02-25 18:49:41 +08:00
commit 23d9e73969
14 changed files with 2364 additions and 0 deletions

107
src/components/FullPage.vue Normal file
View File

@@ -0,0 +1,107 @@
<template>
<div class="fullpage-container" @wheel.prevent="handleWheel" @touchstart="handleTouchStart"
@touchend="handleTouchEnd">
<div class="fullpage-wrapper" :style="wrapperStyle">
<slot />
</div>
<div class="fullpage-dots">
<span v-for="i in pageCount" :key="i" class="dot" :class="{ active: currentIndex === i - 1 }"
@click="goTo(i - 1)" />
</div>
</div>
</template>
<script setup>
import { ref, computed, useSlots } from 'vue'
const slots = useSlots()
const pageCount = computed(() => {
const defaultSlot = slots.default?.()
return defaultSlot ? defaultSlot.length : 0
})
const currentIndex = ref(0)
const isAnimating = ref(false)
const touchStartY = ref(0)
const wrapperStyle = computed(() => ({
transform: `translateY(-${currentIndex.value * 100}vh)`,
transition: isAnimating.value ? 'transform 0.8s cubic-bezier(0.65, 0, 0.35, 1)' : 'none',
}))
function goTo(index) {
if (isAnimating.value || index === currentIndex.value) return
if (index < 0 || index >= pageCount.value) return
isAnimating.value = true
currentIndex.value = index
setTimeout(() => {
isAnimating.value = false
}, 800)
}
function handleWheel(e) {
if (isAnimating.value) return
if (e.deltaY > 0) {
goTo(currentIndex.value + 1)
} else if (e.deltaY < 0) {
goTo(currentIndex.value - 1)
}
}
function handleTouchStart(e) {
touchStartY.value = e.touches[0].clientY
}
function handleTouchEnd(e) {
const deltaY = touchStartY.value - e.changedTouches[0].clientY
if (Math.abs(deltaY) > 50) {
if (deltaY > 0) {
goTo(currentIndex.value + 1)
} else {
goTo(currentIndex.value - 1)
}
}
}
defineExpose({ currentIndex, goTo })
</script>
<style scoped>
.fullpage-container {
width: 100%;
height: 100vh;
overflow: hidden;
position: relative;
}
.fullpage-wrapper {
width: 100%;
will-change: transform;
}
.fullpage-dots {
position: fixed;
right: 30px;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
gap: 12px;
z-index: 100;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
cursor: pointer;
transition: all 0.3s ease;
}
.dot.active {
background: #fff;
transform: scale(1.3);
box-shadow: 0 0 8px rgba(255, 255, 255, 0.6);
}
</style>