Appearance
skewed-infinite-scroll
12312312312
12312312312
12312312312
12312312312
12312312312
12312312312
12312312312
12312312312
<script setup lang='ts'>
// 参考:https://spark-ui.dev/content/components/skewed-infinite-scroll
import { useData } from 'vitepress'
import { computed } from 'vue'
const props = withDefaults(defineProps<{
items: { id: string, text: string }[]
}>(), {
items: () => [{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" },
{ id: '1', text: "12312312312" }
]
})
const { isDark } = useData()
const currentTheme = computed(() => isDark.value ? '#1f2937' : '#f3f4f6')
</script>
<template>
<div>
<div class="flex items-center justify-center">
<div class="relative w-full max-w-screen-lg overflow-hidden" :style="{
maskComposite: 'intersect',
maskImage: `
linear-gradient(to right, transparent, black 5rem),
linear-gradient(to left, transparent, black 5rem),
linear-gradient(to bottom, transparent, black 5rem),
linear-gradient(to top, transparent, black 5rem)
`,
}">
<div class="mx-auto h-96 md:h-full grid animate-skew-scroll grid-cols-1 gap-5 sm:grid-cols-2">
<div v-for="item in props.items" :key="item.id">
<div :key="item.id"
class="flex cursor-pointer w-56 md:w-56 lg:w-72 px-6 py-1 items-center space-x-2 rounded-md border-parent shadow-md transition-all hover:-translate-y-1 hover:translate-x-1 hover:scale-[1.025] hover:shadow-xl ">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"
stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
class="h-6 w-6 flex-none text-red-500">
<path
d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" />
<path d="m9 12 2 2 4-4" />
</svg>
<p class="text-gray-600">
{{ item.text }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.border-parent {
border: 1px solid v-bind(currentTheme);
}
.animate-skew-scroll {
animation: SkewScroll 20s linear infinite;
}
@keyframes SkewScroll {
0% {
transform: rotatex(20deg) rotateZ(-20deg) skewX(20deg) translateZ(0) translateY(0);
}
100% {
transform: rotatex(20deg) rotateZ(-20deg) skewX(20deg) translateZ(0) translateY(-100%);
}
}
</style>
page-scroll
第一屏内容
第二屏内容
<template>
<div class="scroll-container">
<div class="section section-1 bg-slate-600">
第一屏内容
</div>
<div class="section section-2 bg-blue-600">
第二屏内容
</div>
</div>
</template>
<style scoped>
.scroll-container {
height: 50vh;
overflow-y: scroll;
scroll-snap-type: y mandatory;
-webkit-overflow-scrolling: touch;
}
.section {
height: 50vh;
scroll-snap-align: start;
scroll-snap-stop: always;
}
/* 隐藏滚动条但保持功能 */
.scroll-container {
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE and Edge */
}
.scroll-container::-webkit-scrollbar {
display: none;
/* Chrome, Safari, Opera */
}
</style>
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
const container = document.querySelector('.scroll-container')
// 添加平滑滚动效果
container.style.scrollBehavior = 'smooth'
// 防止中间停留
let isScrolling
container.addEventListener('scroll', () => {
window.clearTimeout(isScrolling)
isScrolling = setTimeout(() => {
const scrollTop = container.scrollTop
const windowHeight = window.innerHeight
const snapPoint = Math.round(scrollTop / windowHeight) * windowHeight
if (scrollTop !== snapPoint) {
container.scrollTo({
top: snapPoint,
behavior: 'smooth'
})
}
}, 50)
})
})
</script>