初始化

This commit is contained in:
李琦
2026-01-15 13:51:44 +08:00
commit b7b6d3e39e
156 changed files with 38913 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
import { onMounted, onBeforeUnmount } from 'vue'
export const useInteractions = () => {
// 滚动进度条
const updateScrollProgress = () => {
const scrollTop = window.scrollY
const docHeight = document.documentElement.scrollHeight
const winHeight = window.innerHeight
const scrollPercent = scrollTop / (docHeight - winHeight)
const progressBar = document.getElementById('scroll-progress')
if (progressBar) {
progressBar.style.width = `${scrollPercent * 100}%`
}
}
// 鼠标倾斜效果
const initTiltEffect = () => {
const tiltCards = document.querySelectorAll('.tilt-card')
tiltCards.forEach(card => {
card.addEventListener('mousemove', (e) => {
const cardRect = card.getBoundingClientRect()
const x = e.clientX - cardRect.left
const y = e.clientY - cardRect.top
const xPercent = (x / cardRect.width) * 100
const yPercent = (y / cardRect.height) * 100
card.style.setProperty('--mouse-x', `${xPercent}%`)
card.style.setProperty('--mouse-y', `${yPercent}%`)
})
})
}
// 初始化所有交互功能
const init = () => {
// 初始化Lucide图标
if (window.lucide) {
window.lucide.createIcons()
}
// 添加滚动事件监听
window.addEventListener('scroll', updateScrollProgress)
// 初始化倾斜效果
initTiltEffect()
}
// 清理资源
const cleanup = () => {
window.removeEventListener('scroll', updateScrollProgress)
}
onMounted(() => {
init()
})
onBeforeUnmount(() => {
cleanup()
})
return {
updateScrollProgress,
initTiltEffect
}
}

View File

@@ -0,0 +1,35 @@
import { onMounted, onUnmounted } from 'vue'
export function useScrollAnimation() {
let observer: IntersectionObserver | null = null
const observe = () => {
observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible')
// Optional: Stop observing once visible
// observer?.unobserve(entry.target)
}
})
}, {
threshold: 0.1,
rootMargin: '50px' // Pre-load slightly before element comes into view
})
document.querySelectorAll('.animate-slide-down, .animate-reveal').forEach(el => {
observer?.observe(el)
})
}
onMounted(() => {
// Small delay to ensure DOM is ready
setTimeout(observe, 100)
})
onUnmounted(() => {
if (observer) {
observer.disconnect()
}
})
}

View File

@@ -0,0 +1,43 @@
export const useToast = () => {
const showToast = (message: string, type: 'success' | 'error' = 'success') => {
const container = document.getElementById('toast-container')
if (!container) return
const toast = document.createElement('div')
toast.className = `toast ${type === 'success' ? 'toast-success' : 'toast-error'}`
toast.innerHTML = `
<i data-lucide="${type === 'success' ? 'check-circle' : 'alert-circle'}" class="w-5 h-5 ${type === 'success' ? 'text-[#d4b383]' : 'text-red-500'}"></i>
<span class="text-sm font-medium">${message}</span>
`
container.appendChild(toast)
// 初始化Lucide图标
if (window.lucide) {
window.lucide.createIcons()
}
// 显示动画
requestAnimationFrame(() => toast.classList.add('show'))
// 3秒后自动隐藏
setTimeout(() => {
toast.classList.remove('show')
setTimeout(() => toast.remove(), 400)
}, 3000)
}
// 便捷方法
const success = (message: string) => {
showToast(message, 'success')
}
const error = (message: string) => {
showToast(message, 'error')
}
return {
showToast,
success,
error
}
}