Vue.js预加载器组件加载、页面跳转后不消失问题排查与解决
问题根因
document.onreadystatechange仅监听浏览器原生文档的全量加载状态,Vue单页应用的路由跳转是组件级别的局部重渲染,不会触发浏览器原生文档加载状态的变更,因此跳转后绑定的监听回调不会执行,isloaded始终为初始值false,预加载器会持续显示。
修复方案
首先删除原有mounted中绑定document.onreadystatechange的逻辑,根据预加载器的放置位置选择对应实现:
方案1:预加载器为全局公共组件(放置在App.vue根组件)
通过监听路由变化控制预加载器状态,路由开始跳转时显示预加载器,页面DOM渲染完成后自动隐藏:
<template> <div class="page-loader" v-if="!isloaded"> <div class="cube"></div> <div class="cube"></div> <div class="cube"></div> <div class="cube"></div> </div> <router-view /> </template> <script> export default { data() { return { isloaded: false } }, mounted() { // 首次进入页面渲染完成后隐藏预加载器 this.isloaded = true }, watch: { $route() { // 路由触发跳转时显示预加载器 this.isloaded = false // 等待DOM更新渲染完成后隐藏预加载器 this.$nextTick(() => { this.isloaded = true }) } } } </script>
如果页面首屏存在接口请求、大图加载等异步逻辑,不要直接在
$nextTick中修改状态,需要等所有首屏异步资源加载完成后,再将isloaded设为true,避免预加载器提前消失出现页面空白。
方案2:预加载器为页面级组件(每个业务页面单独引入)
不需要额外监听路由,直接利用组件自身的生命周期控制状态即可,每次路由切换进入页面、组件重新挂载时都会触发逻辑:
<template> <div class="page-loader" v-if="!isloaded"> <div class="cube"></div> <div class="cube"></div> <div class="cube"></div> <div class="cube"></div> </div> <!-- 页面业务内容 --> </template> <script> export default { data() { return { isloaded: false } }, mounted() { // 组件挂载、DOM渲染完成后隐藏预加载器 // 存在异步加载逻辑时,将该行移到异步请求的最终回调中执行 this.isloaded = true } } </script>
注意事项
- Vue单页应用场景下不要依赖原生
document.readyState判断页面渲染状态,路由切换不会触发该状态变更 - 原代码中
data使用箭头函数的写法存在隐患,箭头函数不会绑定组件实例作为this,后续逻辑需要依赖组件实例时会出现异常,建议改成普通函数写法 - 涉及异步资源加载的场景,务必等首屏所需的接口、图片等资源全部加载完成后再关闭预加载器
内容的提问来源于stack exchange,提问作者JT Simon
相关产品推荐
相关产品推荐

