需求简介
自从公司裁员后,每个人手上的活而越来越多,老板给了我个需求,让我尽快实现,不然立马滚蛋!
我大脑飞速思索,1秒后终于反应过来,不就是个滚动条滚动加css吗,还想辞退我,做梦!不能惯着!
技术方案
技术选型
首先,很快啊,我就实现了静态样式
然后要考虑的就是如何实现点击锚点界面能滚动到对应的模块,最简单的就是scrollIntoView
方法。
Element 接口的 scrollIntoView()
方法会滚动元素的父容器,使被调用 scrollIntoView()
的元素对用户可见。
至于闪烁突出,那就当元素被选中时,给它动态添加一个类名,写写css动画就行。
以vue为例,我具体展示下实现过程。
实现滚动
点击导航栏的得锚点时,我们可以使用wacth
监听到是哪个模块被点击了,然后执行滚动逻辑。
<template>
<div class="card-content" >
<!-- 模块内容 -->
</div>
</template>
<script setup lang="ts">
// 监听被点击的模块编码,执行滚动逻辑
watch(() => scrollModuleCode, (v) => {
// 滚动逻辑
})
</script>
我们先看看scrollIntoView的简单用法
Element.scrollIntoView()
Element 接口的 scrollIntoView() 方法会滚动元素的父容器,使被调用 scrollIntoView() 的元素对用户可见。
语法
scrollIntoView(scrollIntoViewOptions)
使用示例
const element = document.getElementById("box");
element.scrollIntoView();
element.scrollIntoView({ block: "end" });
element.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
属性参数释义
behavior (可选)
定义滚动是立即的还是平滑的动画。该选项是一个字符串,必须采用以下值之一:
- smooth:滚动应该是平滑的动画。
- instant:滚动应该通过一次跳跃立刻发生。
- auto:滚动行为由 scroll-behavior 的计算值决定。
滚动实现
结合scrollIntoView
的用法,要实现滚动就非常容易了
<template>
<div class="card-content" ref="scrollRef">
<!-- 模块内容 -->
</div>
</template>
<script setup lang="ts">
const scrollRef = ref()
// 监听被点击的模块编码,执行滚动逻辑
watch(() => scrollModuleCode, (v) => {
// 滚动逻辑
nextTick(() => {
scrollRef.value.scrollIntoView({ behavior: "smooth", block: "start" });
})
})
</script>
上述代码中,我们使用scrollRef绑定了元素的dom,当元素被点击时,实现了滚动。看看效果
不错,基本功能实现了,现在我们增加下样式。
闪烁突出实现
要实现闪烁动画,我们可以再模块被点击时,动态添加一个类名,然后给这个类写样式即可。
<template>
<div class="card-content" ref="scrollRef" :class="{ 'stroke-flash': flashActive }">
<!-- 模块内容 -->
</div>
</template>
<script setup lang="ts">
const scrollRef = ref()
const flashActive = ref(false)
// 监听被点击的模块编码,执行滚动逻辑
watch(() => scrollModuleCode, (v) => {
// 开启动画
flashActive.value = true
// 滚动逻辑
nextTick(() => {
scrollRef.value.scrollIntoView({ behavior: "smooth", block: "start" });
})
// 关闭动画
setTimeout(() => {
flashActive.value = false
}, 2200)
})
</script>
<style>
.stroke-flash {
}
</style>
上述代码中,当模块被点击时,flashActive值变为true,组件的stroke-flash类名被激活,2.2s后,flashActive值变为fasle,类名消失,动画结束。
那么样式如何实现呢?突出闪烁,其实就是给组件加个蓝色的边框,然后使用动画属性改变其透明度。
@keyframes strokeFlash {
0%,
100% {
border-color: transparent;
}
50% {
border: 3px solid #246FE5;
}
}
.stroke-flash {
/* 动画名称、动画时长、缓入缓出效果、循环次数 */
border-radius: 12px;
animation: strokeFlash 1100ms ease-in-out 2;
}
我们看看效果
nice!
仔细观察界面,其实有个非常难受的地方,每次滚动,元素总是滚动到了浏览器视窗的顶部,导致有一部分被导航栏遮住了,非常难受!这要是给老板交付,搞不好直接被裁了!
滚动位置优化
一个很难受的地方就是scrollIntoView()
不支持传元素滚动到浏览器顶部的距离,这导致每次滚动元素都定位到了浏览器顶部。比如,我们更希望点击【控制失调空间】时,界面是这样
而不是直接滚动到浏览器顶部
要解决这个问题,其实很简单!注意看,我给每个模块顶部一定高度写了个专门用于定位的div。
<template>
<div class="card-content":class="{ 'stroke-flash': flashActive }">
<div class="anchor" ref="scrollRef"></div>
<!-- 模块内容 -->
</div>
</template>
<script setup lang="ts">
const scrollRef = ref()
const flashActive = ref(false)
// 监听被点击的模块编码,执行滚动逻辑
watch(() => scrollModuleCode, (v) => {
// 开启动画
flashActive.value = true
// 滚动逻辑
nextTick(() => {
scrollRef.value.scrollIntoView({ behavior: "smooth", block: "start" });
})
// 关闭动画
setTimeout(() => {
flashActive.value = false
}, 2200)
})
</script>
<style>
.card-content {
position: relative;
.anchor {
top: -177px;
left: 0;
width: 20px;
height: 5px;
position: absolute;
background: red;
}
}
</style>
由于【控制失调空间】模块的定位元素在浏览器的顶部,滚动时,位置就如同我们想象的那样了!
非常丝滑!现在我么把这个红色的锚点隐藏起来就行!
<style>
.card-content {
position: relative;
overflow: hidden;
.anchor {
top: -177px;
left: 0;
width: 10px;
height: 1px;
position: absolute;
background: red;
opacity: 0;
}
}
</style>
再试试
这么丝滑,老板肯定不会辞退我了!不说了,去交差了!
写在最后
这个锚点定位+闪烁突出实现的方案比较简单和粗糙,时间紧,任务重,我也没想到很好的方案。。。如果有更好的实现方式,请大家评论区告诉我!我去和老板对线!