提交 92d6fbb5 编写于 作者: Q qq_40591925

Thu Apr 10 16:28:00 CST 2025 inscode

上级 c315236e
<script setup>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
const scrollContainer = ref<HTMLElement | null>(null);
const isSnap = ref<boolean>(true)
const isLeftEdge = ref<boolean>(true)
const isRightEdge = ref<boolean>(false)
const changeScroll=(Dom:HTMLElement,target:number)=>{
const startTime = performance.now();
const startScroll = Dom.scrollLeft;
const duration = 150;
isSnap.value = false;
const animate = (timestamp: number) => {
const progress = (timestamp - startTime) / duration;
if (progress < 1) {
// 线性插值计算当前位置
const current = startScroll + (target - startScroll) * progress;
Dom.scrollLeft = current;
window.requestAnimationFrame(animate);
} else {
// 动画结束,跳转到目标位置(避免误差)
isSnap.value = true;
nextTick(()=>{
setTimeout(()=>{
Dom.scrollLeft = target-1;
},0)
})
}
};
window.requestAnimationFrame(animate);
}
const handleScrollClick=(type:'prev'|'next')=>{
const container = scrollContainer.value
const containerWidth = container?.clientWidth || 0;
const currentScroll = container?.scrollLeft || 0;
let scrollLeft = 0;
if(type==='prev'){
scrollLeft = currentScroll - containerWidth;
}else{
scrollLeft = currentScroll + containerWidth;
}
scrollLeft=scrollLeft<0?0:scrollLeft
// 有动画
changeScroll(container as HTMLElement,scrollLeft)
}
const handleScroll = () => {
if (!scrollContainer.value) return;
const container = scrollContainer.value;
// 当前滚动位置
const currentScroll = container.scrollLeft;
const maxScroll = container.scrollWidth - container.clientWidth - 5
isLeftEdge.value=currentScroll < 5
isRightEdge.value=currentScroll >= maxScroll
};
onMounted(() => {
window.onresize = function () {
const container = scrollContainer.value as HTMLElement;
container.scrollLeft = container.scrollLeft + 1;
}
if (scrollContainer.value) {
scrollContainer.value.addEventListener('scroll', handleScroll);
}
})
onBeforeUnmount(() => {
if (scrollContainer.value) {
scrollContainer.value.removeEventListener('scroll', handleScroll);
}
});
</script>
<template>
<div
ref="scrollContainer"
class="scroll-container"
@scroll="handleScroll"
>
<div class="scroll-content">
<!-- 让第一个元素为 spacer,最左边有间距 -->
<div class="spacer"></div>
<div
v-for="(item, index) in 20"
:key="index"
class="scroll-item"
>
<!-- 元素内容 -->
<div class="firstTitle">最后在h5端看效果</div>
<div class="scroll-main">
<div class="scroll-head">
<div class="title">
提示
</div>
<div class="right">
<div
@click="isLeftEdge ? () => {} : handleScrollClick('prev')"
class="prev"
:class="{ 'lookClick': !isLeftEdge }"
>
<
</div>
<div
@click="isRightEdge ? () => {} : handleScrollClick('next')"
class="next"
:class="{ 'lookClick': !isRightEdge }"
>
>
</div>
</div>
</div>
<div
ref="scrollContainer"
class="scroll-container"
@scroll="handleScroll"
:class="{ 'scroll-snap': isSnap }"
>
<div class="scroll-content">
<div
v-for="(item, index) in 20"
:key="index"
class="scroll-item"
>
<!-- 元素内容 -->
</div>
</div>
<div class="spacer"></div>
</div>
</div>
</template>
<style>
#app{
padding: 0 !important;
}
.firstTitle{
color: #000;
font-size: 16px;
text-align: center;
margin: 20px 0;
}
</style>
<style scoped >
.scroll-main{
margin-top: 10px;
width: 375px;
margin: 0 auto;
}
.scroll-head{
display: flex;
padding: 0 13px;
justify-content: space-between;
align-items: center;
}
.title{
color: #000;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: bolder;
flex: 1;
}
.right{
display: flex;
}
.prev,.next{
display: flex;
border-radius: 4px;
background: #31363A;
display: flex;
width: 30px;
height: 30px;
padding: 10px 8px;
justify-content: center;
align-items: center;
font-size: 14px;
color: #fff;
margin-left: 10px;
cursor: pointer;
}
.lookClick{
background: #394143;
}
<style scoped>
/*下面时滚动的 */
.scroll-container {
margin: 0 auto;
margin: 10px auto;
width: 375px;
overflow-x: auto;
white-space: nowrap;
}
.scroll-container.scroll-snap{
scroll-snap-type: x mandatory; /* 强制滚动到snap目标 */
-webkit-scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch; /* 移动端平滑滚动 */
......@@ -39,6 +199,8 @@
.scroll-content{
display: flex;
width: fit-content;
padding: 0 0.26rem;
}
.spacer{
......@@ -51,14 +213,18 @@
}
.scroll-item {
flex-shrink: 0;
scroll-snap-align: start;
-webkit-scroll-snap-align: start;
scroll-snap-stop:always;
/* scroll-snap-align: start;
-webkit-scroll-snap-align: start; */
/**由于设置了 scroll-margin-left 和 scroll-margin-right 会到导致 scroll-snap-align 的 对齐方式都会受到影响,慎重使用*/
scroll-snap-align: end;
-webkit-scroll-snap-align: end;
display: inline-block;
margin-left: 8px;
margin-left: 6px;
width: 112px;
height: 149px;
background-color: red;
border-radius: 10px;
/*每个 .scroll-item 会向左和向右偏移 13px,视觉效果:滚动到某个元素时,该元素居中,前后元素各露出 13px*/
......@@ -67,7 +233,15 @@
-webkit-scroll-margin-left: 13px;
-webkit-scroll-margin-right: 13px;
}
.scroll-item:nth-child(2){
/* 存在 .spacer 时,第二个子元素(即第一个 .scroll-item) */
.scroll-content > :not(.scroll-item) + .scroll-item {
margin-left: 0;
}
/* 不存在 .spacer 时,第一个子元素就是 .scroll-item */
.scroll-content > .scroll-item:first-child {
margin-left: 0;
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册