Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
寒墨茗殇
h5中 css实现仿卡片切换
提交
92d6fbb5
H
h5中 css实现仿卡片切换
项目概览
寒墨茗殇
/
h5中 css实现仿卡片切换
与 Fork 源项目一致
Fork自
inscode / VueJS
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
h5中 css实现仿卡片切换
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
92d6fbb5
编写于
4月 10, 2025
作者:
Q
qq_40591925
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Thu Apr 10 16:28:00 CST 2025 inscode
上级
c315236e
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
197 addition
and
23 deletion
+197
-23
src/App.vue
src/App.vue
+197
-23
未找到文件。
src/App.vue
浏览文件 @
92d6fbb5
<
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
:
8
px
;
margin-left
:
6
px
;
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录