Vue切换回页面可见状态后,避免执行多次滚动定位的动画
目录
一. 问题场景描述
vue里的一个页面组件涉及到音频文件的自动播放,并且在自动播放时要自动滚动聚焦定位到对应的语音文本列表项,那么当用户点击了自动播放后,点击浏览器的其它标签页页面 或者 打开了电脑的其它软件完全遮盖住了 该页面,那么过了一段时间,再重新查看浏览器的该页面时,该页面里累积的自动滚动聚焦定位动画会连续执行,一直到积攒的未执行的自动滚动聚焦定位动画全部执行完后才会停止,而页面看起来就是连续快速定位多次,会严重影响到用户体验。
二. 问题解决方案
通过监听window对象的visibilitychange事件来知道当前页面的可见性,当页面不可见时保存最后一次应该去滚动定位的锚点,当页面切换回可见状态时,检查是否存在需要去滚动定位的锚点,如果有,则执行一次滚动定位 并清空 保存的 应该去执行滚动定位的锚点。
三. 相关知识点
window对象的visibilitychange事件 可以在 支持W3C规范的现代浏览器上使用,是当页面的可见性状态发生更改时触发的事件,该事件可用于监测页面是否处于活动状态或隐藏状态。
四. 注意点
当页面刚加载时,e.target.visibilityState的值会是"hidden" 而不是 "visible",因为visibilitychange事件是在页面可见性状态发生改变时触发的,而当页面刚加载完成时,默认情况下页面处于隐藏状态,因此事件会被触发,而e.target.visibilityState的值会被设置为"hidden",而非预期的"visible",因此需要针对这个特殊情况进行特殊处理。
五. 相关代码实现
<script>
import VueScrollTo from "vue-scrollto";
const scrolConfig = {
container: "#scroll-area", // 滚动的容器。
duration: 500, // 滚动时间。
easing: "ease", // 缓动类型。 // ease。
offset: -50, // 滚动时应应用的偏移量。此选项接受回调函数。
force: false, // 是否应执行滚动。 // 默认为true,改成false可以改善一下抖动问题。
cancelable: true, // 用户是否可以取消滚动。
onStart: false, // 滚动开始时的钩子函数。
onDone: false, // 滚动结束时候的钩子函数。
onCancel: false, // 用户取消滚动的钩子函数。
x: false, // 是否要在x轴上也滚动。
y: true // 是否要在y轴上滚动。
};
export default {
data() {
return {
pageVisible: false, // 页面是否可见。
isNotFirst:false, // 是否 非首次查看此页面。
lastAnchorId:'', // 页面不可见期间,应定位的最后一个锚点。
};
},
created() {
let that = this;
window.addEventListener('visibilitychange',that.visibleChange);
this.$once('hook:beforeDestroy',()=>{
window.removeEventListener('visibilitychange',that.visibleChange);
})
},
methods: {
async scrollTo(anchorId = "") {
if(this.pageVisible){
this.$nextTick(()=>{
VueScrollTo.scrollTo("#" + anchorId, 500, scrolConfig);
})
}else{
if(this.isNotFirst){
this.lastAnchorId = "#" + anchorId;
}else{
this.$nextTick(()=>{
VueScrollTo.scrollTo("#" + anchorId, 500, scrolConfig);
})
}
}
},
visibleChange:function(e){
if(e.target.visibilityState === "visible"){
this.pageVisible = true;
if(this.lastAnchorId){
let anchorId = this.lastAnchorId;
this.lastAnchorId = '';
this.$nextTick(()=>{
VueScrollTo.scrollTo(anchorId, 500, scrolConfig);
})
}
}else if(e.target.visibilityState === "hidden"){
if(!this.pageVisible){
this.isNotFirst = true; // 如果this.pageVisible前一次值就是false,那么再次为false表示页面可见性改变为真的不可见了,那么再次进入此页面就视为不是第一次打开页面。
}
this.pageVisible = false;
}
}
},
};
<script>