96 UI optimization (#136)
* fix(home): 🐛 解决多次切换路由后页面卡顿的问题 #96 卸载路由时清除requestAnimationFrame * feat: ✨ 文件存储使用Blob格式 * style: 💄 修改部分类型any为具体类型 * feat: ✨ 界面设置中模块使用瀑布流布局 #96 * fix: 🐛 md文档更换文件夹解决控制台警告 * style: 💄 switch按钮改回使用daisyui组件 * refactor: ♻️ 所有人员列表提取tableColumn * style: 💄 奖项列表中的图片类型修复 * fix(globalConfig): 修复当前音乐项类型缺失问题 * feat: ✨ single person not done * feat: ✨ 可添加单人 #96 * build(.gitignore): 添加 auto-imports.d.ts 到忽略文件 * fix: 🐛 上传、下载excel文件时修复路径错误 打包成应用和网页端的baseUrl不一样,使用环境变量来表示 * fix: 🐛 导入人员列表时处理有值为空的情况 * style: 💄 改变toaster的组件 * fix: 🐛 上传文件、解析数据与存储/读取数据的处理 、 * fix(Config): 更新备案信息链接样式 将备案信息的段落标签替换为可点击的链接标签,使用户能够直接跳转到工信部备案查询页面。同时添加了悬停效果样式,提升用户体验。 * feat: ✨ 首页奖项列表样式修改 not done #96 * chore(deps): ✏️ 更新依赖版本 * chore: ✏️ gsap list demo * build: 🏗️ docker构建优化 * chore: ✏️ gsap scroll demo * style: 💄 gsap demno * feat: ✨ demo smooth scroll gsap scrolltrigger * feat(Demo): 添加更多颜色选项并注释GSAP动画 * refactor(PrizeList): 重构奖品列表组件结构 * feat(PrizeList): 重构奖品列表组件并添加滚动动画 * feat: ✨ 增加定时抽取功能 #96 * feat: ✨ 添加定时抽取功能的说明 * feat: ✨ 优化gsap #96 项数不多时不触发gsap * style: 💄 文本修改 * feat: ✨ 优化 * feat: ✨ 优化奖项列表 * fix(Home): 修复奖品列表滚动检测逻辑 * fix(home): 修复抽奖停止逻辑避免重复执行;调整卡片垂直居中位置计算 * feat: ✨ 播放中奖音频 #96
This commit is contained in:
@@ -1,18 +1,241 @@
|
||||
<script setup lang='ts'>
|
||||
import WaterFall from '@/components/Waterfall/index.vue'
|
||||
<script setup lang="ts">
|
||||
import gsap from 'gsap'
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||
import { onBeforeUnmount, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger)
|
||||
|
||||
const list = ref<any[]>([])
|
||||
|
||||
list.value = [{
|
||||
label: 1,
|
||||
value: 1,
|
||||
color: 'red',
|
||||
}, {
|
||||
label: 2,
|
||||
value: 2,
|
||||
color: 'blue',
|
||||
}, {
|
||||
label: 3,
|
||||
value: 3,
|
||||
color: 'yellow',
|
||||
}, {
|
||||
label: 4,
|
||||
value: 4,
|
||||
color: 'green',
|
||||
}, {
|
||||
label: 5,
|
||||
value: 5,
|
||||
color: 'pink',
|
||||
}, {
|
||||
label: 6,
|
||||
value: 6,
|
||||
color: 'orange',
|
||||
}, {
|
||||
label: 7,
|
||||
value: 7,
|
||||
color: 'purple',
|
||||
}, {
|
||||
label: 8,
|
||||
value: 8,
|
||||
color: 'brown',
|
||||
}, {
|
||||
label: 9,
|
||||
value: 9,
|
||||
color: 'gray',
|
||||
}, {
|
||||
label: 10,
|
||||
value: 10,
|
||||
color: 'cyan',
|
||||
}, {
|
||||
label: 11,
|
||||
value: 11,
|
||||
color: 'white',
|
||||
}, {
|
||||
label: 12,
|
||||
value: 12,
|
||||
color: 'black',
|
||||
}, {
|
||||
label: 13,
|
||||
value: 13,
|
||||
color: 'orange',
|
||||
}, {
|
||||
label: 14,
|
||||
value: 14,
|
||||
color: 'yellow',
|
||||
}, {
|
||||
label: 15,
|
||||
value: 14,
|
||||
color: 'pink',
|
||||
}, {
|
||||
label: 15,
|
||||
value: 15,
|
||||
color: 'orange',
|
||||
}, {
|
||||
label: 16,
|
||||
value: 16,
|
||||
color: 'yellow',
|
||||
}, {
|
||||
label: 17,
|
||||
value: 17,
|
||||
color: 'green',
|
||||
}, {
|
||||
label: 18,
|
||||
value: 18,
|
||||
color: 'purple',
|
||||
}]
|
||||
|
||||
// 为每个 li 元素创建引用
|
||||
const liRefs = ref()
|
||||
const scrollContainerRef = ref()
|
||||
const ctx = ref()
|
||||
const showUpButton = ref(false)
|
||||
const showDownButton = ref(true)
|
||||
|
||||
function initGsapAnimation() {
|
||||
ctx.value = gsap.context(() => {
|
||||
liRefs.value.forEach((box: any) => {
|
||||
gsap.fromTo(box, { rotationX: -90, rotateZ: -20, opacity: 0 }, {
|
||||
rotationX: 0,
|
||||
rotateZ: 0,
|
||||
opacity: 1,
|
||||
scrollTrigger: {
|
||||
trigger: box,
|
||||
scroller: scrollContainerRef.value, // <- Specify the scroller!
|
||||
start: 'bottom 100%',
|
||||
end: 'top 70%',
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
})
|
||||
}, scrollContainerRef.value) // <- Scope!
|
||||
}
|
||||
|
||||
function disposeGsapAnimation() {
|
||||
ctx.value.revert() // <- Easy Cleanup!
|
||||
}
|
||||
function scrollHandler() {
|
||||
const scrollHeight = scrollContainerRef.value.scrollHeight
|
||||
const scrollTop = scrollContainerRef.value.scrollTop
|
||||
const containerHeight = scrollContainerRef.value.clientHeight
|
||||
// 滚动滑到底部
|
||||
if (scrollTop + containerHeight >= scrollHeight) {
|
||||
showDownButton.value = false
|
||||
showUpButton.value = true
|
||||
}
|
||||
// 在中间
|
||||
else if (scrollTop && scrollTop + containerHeight < scrollHeight) {
|
||||
showDownButton.value = true
|
||||
showUpButton.value = true
|
||||
}
|
||||
// 滚动滑到顶部
|
||||
else {
|
||||
showDownButton.value = true
|
||||
showUpButton.value = false
|
||||
}
|
||||
}
|
||||
function listenScrollContainer() {
|
||||
scrollContainerRef.value.addEventListener('scroll', scrollHandler)
|
||||
}
|
||||
function removeScrollContainer() {
|
||||
if (scrollContainerRef.value) {
|
||||
scrollContainerRef.value.removeEventListener('scroll', scrollHandler)
|
||||
}
|
||||
}
|
||||
|
||||
function handleScroll(h: number) {
|
||||
scrollContainerRef.value.scrollTop += h
|
||||
}
|
||||
onMounted(() => {
|
||||
initGsapAnimation()
|
||||
listenScrollContainer()
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
removeScrollContainer()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
disposeGsapAnimation()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WaterFall>
|
||||
<div class="bg-pink-500 h-20 w-48" />
|
||||
<div class="bg-blue-500 h-30 w-48" />
|
||||
<div class="bg-yellow-500 h-40 w-48" />
|
||||
<div class="bg-green-500 h-20 w-48" />
|
||||
<div class="bg-red-500 h-30 w-48" />
|
||||
<div class="bg-purple-500 h-50 w-48" />
|
||||
</WaterFall>
|
||||
<div class="h-full w-48 flex flex-col justify-center overflow-hidden relative">
|
||||
<div class="w-full h-16 flex justify-center scroll-button scroll-button-up">
|
||||
<SvgIcon v-show="showUpButton" name="chevron-up" size="64px" class="text-gray-200/80 cursor-pointer" @click="handleScroll(-100)" />
|
||||
</div>
|
||||
<div ref="scrollContainerRef" class="h-150 w-48 overflow-y-auto overflow-x-hidden relative scroll-smooth hide-scrollbar">
|
||||
<ul class="li-container relative bg-slate-500/50">
|
||||
<li
|
||||
v-for="item in list" :key="item.value" ref="liRefs" :style="{ backgroundColor: item.color }"
|
||||
class="w-full h-28 text-center leading-30 cursor-pointer duration-300"
|
||||
>
|
||||
{{ item.label }}
|
||||
</li>
|
||||
<li class="h-16" />
|
||||
</ul>
|
||||
</div>
|
||||
<div class="w-full h-16 flex justify-center scroll-button scroll-button-down">
|
||||
<SvgIcon v-show="showDownButton" name="chevron-down" size="64px" class="text-gray-200/80 cursor-pointer" @click="handleScroll(100)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.scroll-button::before,
|
||||
.scroll-button::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
transform: translate(12px 12px);
|
||||
}
|
||||
|
||||
.scroll-button::before {
|
||||
transform: translate(0, -6px);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.scroll-button::after {
|
||||
transform: translate(0, 6px);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* 添加动画效果 */
|
||||
.scroll-button-down {
|
||||
animation: bounce-down 2s infinite;
|
||||
}
|
||||
/* 添加动画效果 */
|
||||
.scroll-button-up {
|
||||
animation: bounce-up 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes bounce-down {
|
||||
0%, 20%, 50%, 80%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
60% {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
@keyframes bounce-up {
|
||||
0%, 20%, 50%, 80%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateY(5px);
|
||||
}
|
||||
60% {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-button:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user