我们今天来实现一下,点击当前用户的div, 自动滚动到用户在排行榜中的位置.
效果
大家可以先看一下下面的GIF, 所实现的效果.
实现
1. 准备DOM 结构
首先,我们在进行列表建设的时候, 需要准备好一个数据. 因为此处我们是使用的vue3
来进行编写. 对于列表我们使用的是v-for列表渲染
来做的. 在渲染的时候, 我们需要给每一个列表项(当前就是每一个用户项
)添加一个自定义属性. 具体的话, 可以看下 下方的关键代码.
核心代码就是
代码语言:javascript复制 <div v-for="(item, index) in rankingData" :key="item.user.id" :data-key="item.user.id"
</div>
因为数据是后端返回的, 是包含的user_id,而且这个user_id 是不可能重复的. 我们只要保证每个列表的自定义的属性是唯一的即可.
2. 绑定方法,实现方法
接下来,我们需要考虑的是,在点击的时候,如何获取到当前的dom. 这对我们目前来说就很容易了, 因为我们可以根据据user_id
拿到我们当前点击的dom.
添加一个方法
代码语言:javascript复制<!-- 当前用户排名情况 -->
<div class="text-white w-[100%] ...." @click="scrollToCurrentRankingPosition(userId)">
实现方法.
第一步: 拿到rankingList的dom实例.
这里我们通过vue3提供ref拿到dom. 可以看下 模板引用
代码语言:javascript复制<div v-else class=" overflow-auto bg-white" ref="rankingList">
const rankingList = ref(null);
第二步: 根据userId获取到具体的DOM
代码语言:javascript复制const currentItem = rankingList.value.querySelector(`[data-key="${id}"]`);
第三步: 使用scrollIntoView方法滚动视图到当前选中的元素
代码语言:javascript复制 // 平滑滚动到当前元素
currentItem.scrollIntoView({ behavior: 'smooth', block: 'center' });
scrollIntoView方法 讲解:
Element
接口的scrollIntoView()
方法会滚动元素的父容器,使被调用scrollIntoView()
的元素对用户可见。
简单来讲就是被调用的者的元素出现在用户的视线里面. scrollIntoView()
方法有三种调用形式:
scrollIntoView()
:无参数调用,元素将滚动到可视区域顶部,如果它是第一个可见元素。scrollIntoView(alignToTop)
:接受一个布尔值参数,决定元素是与滚动区的顶部还是底部对齐。scrollIntoView(scrollIntoViewOptions)
:接受一个对象作为参数,提供了更多的滚动选项。
参数
-
alignToTop
(可选):布尔值,控制元素滚动到顶部还是底部对齐。默认为true
(顶部对齐)。 -
scrollIntoViewOptions
(可选实验性):对象,包含以下属性:behavior
:定义滚动行为是平滑动画还是立即发生。可取值有smooth
(平滑动画)、instant
(立即发生)或auto
(由CSS的scroll-behavior
属性决定)。block
:定义垂直方向的对齐方式,可取值有start
、center
、end
或nearest
。默认为start
。inline
:定义水平方向的对齐方式,可取值有start
、center
、end
或nearest
。默认为nearest
。
目前我们实现了效果.
但是我们发现,还可以继续改进, 目前我们虽然滚动到了屏幕的中间, 但是我们很难去发现. 所以我们可以继续完善一下这个方法. 就是滚动到视图的中间的同时高亮选中的DOM.
3. 额外扩展, 高亮当前的元素
定义一个两个方法,一个用于应用样式
, 一个应用于移除样式
.
const applyHighlightStyles = (element) => {
element.style.transition = 'background-color 1s ease, border-color 1s ease';
element.style.border = '1px solid transparent'; // 预定义边框样式
element.style.borderColor = '#006cfe'; // 设置边框颜色
element.style.backgroundColor = '#cfe5ff'; // 设置背景色为浅蓝色
};
const removeHighlightStyles = (element) => {
element.style.backgroundColor = ''; // 移除背景色
element.style.borderColor = 'transparent'; // 移除边框颜色
};
然后再在我们之前的方法的后面加入代码
代码语言:javascript复制 // 设置高亮显示的样式
applyHighlightStyles(currentItem);
// 清除之前的定时器(如果有)
if (currentItem._highlightTimer) {
clearTimeout(currentItem._highlightTimer);
}
// 设置定时器,2秒后移除高亮显示
currentItem._highlightTimer = setTimeout(() => {
removeHighlightStyles(currentItem);
currentItem._highlightTimer = null;
}, 2000);
然后在组件卸载前记得清除定时器.
代码语言:javascript复制onUnmounted(() => {
if (rankingList.value) {
// 遍历所有项目,清除定时器
rankingList.value.querySelectorAll('[data-key]').forEach(item => {
if (item._highlightTimer) {
clearTimeout(item._highlightTimer);
item._highlightTimer = null;
}
});
}
});
效果:
总结
整体下来的思路就是:
- v-for的时候, 给每个循环的元素添加一个自定义的属性.(value:user_id), 不重复且能标识每个元素.
- 点击之后,拿到id,透传给方法,然后通过id获取到当前的元素.
- 使用
Element.scrollIntoView()
, 将当前的选中的DOM自动滚动视图的中间. - 高亮显示当前的元素之后(2s)进行取消高亮.