当前位置: 首页 > Web前端 > vue.js

为Vue的懒加载添加进度条

时间:2023-03-31 21:19:22 vue.js

.loading-container{font-size:0;位置:固定;顶部:0;左:0;高度:5px;宽度:100%;不透明度:0;显示:无;z-指数:100;过渡:不透明度200;}.loading-container.visible{显示:块;}.loading-container.loading{不透明度:1;}.loader{背景:#23d6d6;显示:内联块;高度:100%;宽度:50%;溢出:隐藏;边界半径:005px0;transition:200widthease-out;}.loader>.light{float:right;高度:100%;宽度:20%;背景图像:线性渐变(向右,#23d6d6,#29ffff,#23d6d6);动画:loading-animation2sease-ininfinite;}.glow{display:inline-block;高度:100%;宽度:30px;左边距:-30px;边界半径:005px0;box-shadow:0010px#23d6d6;}@keyframesloading-animation{0%{margin-right:100%;}50%{右边距:100%;}100%{右边距:-10%;}}作者:StackAbuse应用时(SPA),页面加载时,JavaScript、CSS文件等所有需要的资源一起加载。在处理大文件时,这可能会导致糟糕的用户体验。使用Webpack,可以使用import()函数而不是import关键字在Vue.js中按需加载页面。为什么按需加载?SPA在Vue.js中的典型工作方式是将所有功能和资源一起打包和交付,以便用户无需刷新页面即可使用您的应用程序。如果您没有明确地将您的应用程序设计为按需页面加载,所有页面将被一次加载,或者不必要地提前使用大量内存进行预加载。这对于页面很多的大型SPA来说是非常糟糕的,导致低端手机的用户体验很差,网速也很慢。通过按需加载,用户无需下载他们当前不需要的资产。Vue.js没有为动态模块提供任何与加载指示器相关的控件。即使进行了预取和预加载,也没有相应的空间让用户知道加载过程,所以需要增加一个进度条来提高用户体验。准备项目首先需要一个进度条与VueRouter通信的方式。事件总线模式更合适。事件总线是Vue实例的单例。由于所有Vue实例都有一个使用$on和$emit的事件系统,您可以使用它在应用程序的任何地方传递事件。首先在components目录下新建一个文件eventHub.js:importVuefrom'vue'exportdefaultnewVue()然后配置webpack禁用预取和预加载,这样就可以对每个函数单独做这个了,当然你也可以全局禁用它。在根目录下创建一个vue.config.js文件并添加相关配置以禁用预取和预加载:module.exports={chainWebpack:(config)=>{//禁用预取和预加载config.plugins。delete('prefetch')config.plugins.delete('preload')},}添加路由和页面使用npx安装Vue路由器并使用:$npxvueaddrouter编辑位于router/index.js下的路由器文件并更新route,这样就可以使用import()函数来代替import语句:默认配置如下:importAboutfrom'../views/About.vue'{path:'/about',name:'About',component:About},设置改成:{path:'/about',name:'About',component:()=>import('../views/About.vue')},如果你愿意可以选择按需加载一些页面,而不是全局禁用预取和预加载,可以使用特殊的Webpack注解,不要在vue.config.js中配置Webpack:import(/*webpackPrefetch:true*//*webpackPreload:true*/'../views/About.vue')import()和import的主要区别在于,import()加载的ES模块是在运行时加载的,而import加载的ES模块是在编译时加载的。这意味着import()可以用来延迟模块的加载,只在必要时加载它们。实现进度条我们无法真正创建进度条,因为我们无法准确估计页面何时加载(或完全加载)。也没有办法检查页面加载了多少。但是,可以创建一个进度条并在页面加载时让它完成。所描述的进度只是随机跳跃,因为它并没有真正反映进度。首先安装lodash.random,因为在生成进度条的过程中会用到这个包来生成一些随机数:$npmilodash.random然后,创建一个Vue组件components/ProgressBar.vue:class="{'loading-container':true,loading:isLoading,visible:isVisible}">

接下来给这个组件添加脚本。先在脚本中导入random和$eventHub,后面会用到:scriptVariablestobeusedlater://假设加载将在这段时间内完成。constdefaultDuration=8000//更新频率constdefaultInterval=1000//取值范围0-1。每个时间间隔的进度增加多少constvariation=0.5//0-100。进度条应该从多少开始。conststartingPoint=0//限制进度条到达加载完成前的距离constendingPoint=90然后编写实现异步加载组件的逻辑:exportdefault{name:'ProgressBar',data:()=>({isLoading:true,//加载完成后,开始逐渐消失isVisible:false,//动画完成后,设置display:noneprogress:startingPoint,timeoutId:undefined,}),mounted(){$eventHub.$on('asyncComponentLoading',this.start)$eventHub.$on('asyncComponentLoaded',this.stop)},方法:{start(){this.isLoading=truethis.isVisible=truethis.progress=startingPointthis.loop()},loop(){if(this.timeoutId){clearTimeout(this.timeoutId)}if(this.progress>=endingPoint){return}constsize=(endingPoint-startingPoint)/(defaultDuration/defaultInterval)constp=Math.round(this.progress+random(size*(1-变化),大小*(1+变化)))this.progress=Math.min(p,endingPoint)this.timeoutId=setTimeout(this.loop,random(defaultInterval*(1-variation),defaultInterval*(1+variation))},stop(){this.isLoading=falsethis.progress=100clearTimeout(this.timeoutId)constself=thissetTimeout(()=>{if(!self.isLoading){self.isVisible=false}},200)},},}在mounted()函数中,使用事件总线监听异步组件的加载。一旦路由告诉我们已经导航到尚未加载的页面,它将开始加载动画。最后添加一些样式:.loading-container{font-size:0;位置:固定;顶部:0;左:0;高度:5px;宽度:100%;不透明度:0;显示:无;z-指数:100;过渡:不透明度200;}.loading-container.visible{显示:块;}.loading-container.loading{不透明度:1;}.loader{背景:#23d6d6;显示:内联块;高度:100%;宽度:50%;溢出:隐藏;边界半径:005px0;transition:200widthease-out;}.loader>.light{float:right;高度:100%;宽度:20%;背景图像:线性渐变(向右,#23d6d6,#29ffff,#23d6d6);动画:loading-animation2sease-ininfinite;}.glow{display:inline-block;高度:100%;宽度:30px;左边距:-30px;边界半径:005px0;box-shadow:0010px#23d6d6;}@keyframesloading-animation{0%{margin-right:100%;}50%{右边距:100%;}100%{右边距:-10%;}}最后在App.vue或者layout组件中添加ProgressBar,只要和路由视图在同一个组件中,在app的整个生命周期中都是可用的Available:然后在页面顶部可以看到一个流畅的进度条:懒加载的触发进度条现在ProgressBar正在监听事件总线当以这种方式加载某些资源时,应该触发异步组件加载事件和动画。现在向路由添加路由守卫以接收以下事件:import$eventHubfrom'../components/eventHub'router.beforeEach((to,from,next)=>{if(typeofto.matched[0]?.components.default==='function'){$eventHub.$emit('asyncComponentLoading',to)//启动进度条}next()})router.beforeResolve((to,from,next)=>{$eventHub.$emit('asyncComponentLoaded')//停止进度条next()})为了检测页面是否懒加载,需要检查组件是否定义为动态导入,即应该是component:()=>import('...')而不是component:MyComponent。这是通过typeofto.matched[0]?.components.default==='function'完成的。具有import语句的组件不属于函数。总结在本文中,我们在Vue应用程序中禁用了预取和预加载,并创建了一个进度条组件,可以显示该组件以模拟加载页面时的实际进度。