当前位置: 首页 > 科技观察

为Vue的延迟加载添加进度条

时间:2023-03-19 18:32:20 科技观察

.loading-container{font-size:0;position:fixed;top:0;left:0;height:5px;width:100%;opacity:0;display:none;z-index:100;transition:opacity200;}.loading-container.visible{display:block;}.loading-container.loading{opacity:1;}.loader{background:#23d6d6;display:inline-block;height:100%;宽度:50%;溢出:隐藏;边框半径:005px0;过渡:200widthease-out;}.loader>.light{float:right;height:100%;width:20%;background-image:linear-gradient(toright,#23d6d6,#29ffff,#23d6d6);动画:loading-animation2sease-ininfinite;}.glow{display:inline-block;height:100%;width:30px;margin-left:-30px;border-radius:005px0;box-shadow:0010px#23d6d6;}@keyframesloading-animation{0%{margin-right:100%;}50%{margin-right:100%;}100%{margin-right:-10%;}}简介通常在用Vue.js写单页面应用程序(SPA)时,页面加载时,所有需要的资源(如JavaScript和CSS文件)都会一起加载。在处理大文件时,这可能会导致糟糕的用户体验。使用Webpack,可以使用import()函数而不是import关键字在Vue.js中按需加载页面。为什么按需加载?Vue.js中SPA的典型工作方式是将所有功能和资源一起打包和交付,以便用户无需刷新页面即可使用您的应用程序。如果您没有明确地将您的应用程序设计为按需页面加载,所有页面将被一次加载,或者不必要地提前使用大量内存进行预加载。这对于页面很多的大型SPA来说是非常糟糕的,导致低端手机的用户体验很差,网速也很慢。通过按需加载,用户无需下载他们当前不需要的资产。Vue.js没有为动态模块提供任何与加载指示器相关的控件。即使进行了预取和预加载,也没有相应的空间让用户知道加载过程,所以需要增加一个进度条来提高用户体验。准备项目首先需要一个进度条与VueRouter通信的方式。事件总线模式更合适。事件总线是Vue实例的单例。由于所有Vue实例都有一个使用$on和$emit的事件系统,您可以使用它在应用程序的任何地方传递事件。首先在components目录下新建一个文件eventHub.js:importVuefrom'vue'exportdefaultnewVue()然后配置Webpack禁用预取和预加载,这样你就可以针对每个功能单独进行这样的操作,当然你也可以全局禁用。在根文件夹下创建一个vue.config.js文件,并添加相关配置来禁用预取和预加载:module.exports={chainWebpack:(config)=>{//Disableprefetchingandpreloadingconfig.plugins。delete('prefetch')config.plugins.delete('preload')},}添加路由和页面使用npx安装Vue路由器并使用:$npxvueaddrouter编辑位于router/index.js下的路由器文件并更新路由,以便可以将import语句替换成import()函数:如下默认配置:importAboutfrom'../views/About.vue'{path:'/about',name:'About',component:About},改一下to:{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:接下来向该组件添加脚本。先在脚本中导入random和$eventHub,后面会用到:稍后使用变量来://假设加载将在这段时间内完成。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-variation)),size*(1+variation)))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;position:fixed;top:0;left:0;height:5px;width:100%;opacity:0;display:none;z-index:100;transition:opacity200;}.loading-container.visible{display:block;}.loading-container.loading{opacity:1;}.loader{background:#23d6d6;display:inline-block;height:100%;宽度:50%;溢出:隐藏;边框半径:005px0;过渡:200widthease-out;}.loader>.light{float:right;height:100%;width:20%;background-image:linear-gradient(toright,#23d6d6,#29ffff,#23d6d6);动画:loading-animation2sease-ininfinite;}.glow{display:inline-block;height:100%;width:30px;margin-left:-30px;border-radius:005px0;box-shadow:0010px#23d6d6;}@keyframesloading-animation{0%{margin-right:100%;}50%{margin-right:100%;}100%{margin-right:-10%;}}.loading-container{字体大小:0;位置:固定;顶部:0;左:0;高度:5px;宽度:100%;不透明度:0;显示:无;z-指数:100;过渡:不透明度200;}.loading-container.visible{display:block;}.loading-container.loading{opacity:1;}.loader{background:#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的整个生命周期中都是可用的:然后在顶部就可以看到了页面要流畅的进度条:页面顶部的进度条触发延迟加载的进度条现在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()})为了检测页面是否延迟加载,需要检查组件是否定义为动态导入,即应该是组件:()=>import('...')而不是component:MyComponent。这是通过typeofto.matched[0]?.components.default==='function'完成的。具有import语句的组件不属于函数。总结在本文中,我们在Vue应用程序中禁用了预取和预加载,并创建了一个进度条组件,可以显示该组件以模拟加载页面时的实际进度。