各位大佬,对于vue中渲染列表时,我想知道如何比较友好的产生“元素进入可视区事件”?
举例说明:
如图所示,绿色中框为用户可视区(ul),9个蓝色框分别为信息条(li)。
可视区限制一定高度,产生纵向滚动条。2-7元素在可视区中,认为用户已读。1元素在上方,则忽略即认为已读。8、9在下方,还未出现,则认为未读。
我想知道,有没有什么事件可以绑定在li上,当8、9滑动到可视区时自动产生事件将其更为已读。
目前只能想到两个方法。
其一:
<ul class="messages">
<li v-for="message in messages" v-bind:id="message.id"><li>
</ul>
<script>
export default {
name: 'App',
data(){
messages: []
},
methods:{
onScroll(){
let range = [$(".messages").offset().top,$(".messages").offset().top+$(".messages").height()];
$('.messages li').each(function(){
// 判断元素进入可视区
if($(this).offset().top >= range[0] && $(this).offset().top <= range[1]){
let id = $(this).prop('id');
for(let i in this.messages){
if(this.messages[i].id == id){
this.messages[i].status = 'read';
}
}
}
});
}
}
}
//
</script>
简单说说,这个方法,外露一个id属性,给js去遍历,然后再更新到data。
因为需要外露一个属性,感觉不是很好。
其二:
这个可以隐藏id,但是感觉也不是很好。
<ul class="messages">
<li v-for="message in messages" v-bind:id="message.id" @click="message.status='read'"><li>
</ul>
<script>
export default {
name: 'App',
data(){
messages: []
},
methods:{
onScroll(){
let range = [$(".messages").offset().top,$(".messages").offset().top+$(".messages").height()];
$('.messages li').each(function(){
// 判断元素进入可视区
if($(this).offset().top >= range[0] && $(this).offset().top <= range[1]){
$(this).click();
}
});
}
}
}
//
</script>
此方法根据方法一稍微改改,通过click事件触发已读功能。(本想用焦点进入、其他事件、自定义事件结果都不好使)
我觉得这个相比比方法一好,目前也在用。缺点是如果li如果有其他事件,就需要混写在一起,感觉不好。
其次是,滚动事件每一次都要全量foreach一遍页面元素,感觉这个不是很妙。
各位sf的大佬,有没有好的解决方案呢?
我搜索时还发现一个“IntersectionObserver
”相关的,由于不是专业前端,不太清楚这个也没细研究。
使用
Intersection Observer
,我以前写过一篇博客,可以看一下:《Intersection Observer 笔记》。简单来说,就是浏览器提供了一个原生 API 可以监控一个 DOM 的显示/隐藏,及百分比,接下来我们就可以组合使用,实现一些功能。写成代码大概是这样: