In der folgenden Vue.js-Kolumne erfahren Sie, wie Sie Vues Lazy Loading einen Fortschrittsbalken hinzufügen. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.
Normalerweise werden beim Schreiben einer Single-Page-Anwendung (SPA) mit Vue.js beim Laden der Seite alle erforderlichen Ressourcen (z. B. JavaScript- und CSS-Dateien) zusammen geladen. Dies kann bei der Arbeit mit großen Dateien zu einer schlechten Benutzererfahrung führen.
Mit Webpack können Sie die Funktion import()
anstelle des Schlüsselworts import
verwenden, um Seiten bei Bedarf in Vue.js zu laden. import()
函数而不是 import
关键字在 Vue.js 中按需加载页面。
Vue.js 中 SPA 的典型工作方式是将所有功能和资源打包一并交付,这样可以使用户无需刷新页面即可使用你的应用。如果你没有为了按需加载页面针对自己的应用进行明确的设计,那么所有的页面会被立即加载,或者提前使用大量内存进行不必要的预加载。
这对有许多页面的大型 SPA 非常不利,会导致使用低端手机和低网速的用户体验会很差。如果通过按需加载,用户将不需要下载他们当前不需要的资源。
Vue.js 没有为动态模块提供任何加载指示器相关的控件。即使进行了预取和预加载,也没有对应的空间让用户知道加载的过程,所以还需要通过添加进度条来改善用户体验。
首先需要一种让进度条与 Vue Router 通信的方法。事件总线模式比较合适。
事件总线是一个 Vue 实例的单例。由于所有 Vue 实例都有一个使用 $on
和 $emit
的事件系统,因此可以用它在应用中的任何地方传递事件。
首先在 components
目录中创建一个新文件 eventHub.js
:
import Vue from 'vue' export default new Vue()
然后把 Webpack 配置为禁用预取和预加载,这样就可以针对每个函数单独执行此类操作,当然你也可以全局禁用它。在根文件夹中创建一个 vue.config.js
文件并添加禁用预取和预加载的相关配置:
module.exports = { chainWebpack: (config) => { // 禁用预取和预加载 config.plugins.delete('prefetch') config.plugins.delete('preload') }, }
用 npx
安装 Vue router 并使用:
$ npx vue add router
编辑位于 router/index.js
下的 router 文件并更新路由,以便可以用 import()
函数代替 import
语句:
以下默认配置:
import About from '../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
,因为在生成进度条的过程中将会用这个包产生一些随机数:
$ npm i lodash.random
然后,创建一个 Vue 组件 components/ProgressBar.vue
:
<template> <p> </p> <p> </p> <p></p> <p></p> </template>
接下来向该组件添加脚本。在脚本中先导入 random
和 $eventHub
,后面会用到:
<script> import random from 'lodash.random' import $eventHub from '../components/eventHub' </script>
导入之后,在脚本中定义一些后面要用到的变量:
// 假设加载将在此时间内完成。 const defaultDuration = 8000 // 更新频率 const defaultInterval = 1000 // 取值范围 0 - 1. 每个时间间隔进度增长多少 const variation = 0.5 // 0 - 100. 进度条应该从多少开始。 const startingPoint = 0 // 限制进度条到达加载完成之前的距离 const endingPoint = 90
然后编码实现异步加载组件的逻辑:
export default { name: 'ProgressBar', data: () => ({ isLoading: true, // 加载完成后,开始逐渐消失 isVisible: false, // 完成动画后,设置 display: none progress: startingPoint, timeoutId: undefined, }), mounted() { $eventHub.$on('asyncComponentLoading', this.start) $eventHub.$on('asyncComponentLoaded', this.stop) }, methods: { start() { this.isLoading = true this.isVisible = true this.progress = startingPoint this.loop() }, loop() { if (this.timeoutId) { clearTimeout(this.timeoutId) } if (this.progress >= endingPoint) { return } const size = (endingPoint - startingPoint) / (defaultDuration / defaultInterval) const p = 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 = false this.progress = 100 clearTimeout(this.timeoutId) const self = this setTimeout(() => { if (!self.isLoading) { self.isVisible = false } }, 200) }, }, }
在 mounted()
函数中,用事件总线来侦听异步组件的加载。一旦路由告诉我们已经导航到尚未加载的页面,它将会开始加载动画。
最后其添加一些样式:
<style> .loading-container { font-size: 0; position: fixed; top: 0; left: 0; height: 5px; width: 100%; opacity: 0; display: none; z-index: 100; transition: opacity 200; } .loading-container.visible { display: block; } .loading-container.loading { opacity: 1; } .loader { background: #23d6d6; display: inline-block; height: 100%; width: 50%; overflow: hidden; border-radius: 0 0 5px 0; transition: 200 width ease-out; } .loader > .light { float: right; height: 100%; width: 20%; background-image: linear-gradient(to right, #23d6d6, #29ffff, #23d6d6); animation: loading-animation 2s ease-in infinite; } .glow { display: inline-block; height: 100%; width: 30px; margin-left: -30px; border-radius: 0 0 5px 0; box-shadow: 0 0 10px #23d6d6; } @keyframes loading-animation { 0% { margin-right: 100%; } 50% { margin-right: 100%; } 100% { margin-right: -10%; } } </style>
最后将 ProgressBar
添加到 App.vue
或布局组件中,只要它与路由视图位于同一组件中即可,它在应用的整个生命周期中都可用:
<template> <p> <progress-bar></progress-bar> <router-view></router-view> <!--- 你的其它组件 --> </p> </template> <script> import ProgressBar from './components/ProgressBar.vue' export default { components: { ProgressBar }, } </script>
然后你就可以在页面顶端看到一个流畅的进度条:
现在 ProgressBar
$on
und $emit
verfügen, können Sie dieses verwenden, um Ereignisse überall in Ihrer Anwendung bereitzustellen. 🎜🎜Erstellen Sie zunächst eine neue Datei eventHub.js
im Verzeichnis components
: 🎜import $eventHub from '../components/eventHub' router.beforeEach((to, from, next) => { if (typeof to.matched[0]?.components.default === 'function') { $eventHub.$emit('asyncComponentLoading', to) // 启动进度条 } next() }) router.beforeResolve((to, from, next) => { $eventHub.$emit('asyncComponentLoaded') // 停止进度条 next() })
vue.config.js
-Datei im Stammordner und fügen Sie die entsprechende Konfiguration hinzu, um das Vorabrufen und Vorladen zu deaktivieren: 🎜rrreee🎜Routen und Seiten hinzufügen🎜🎜Verwenden Sie npx
. Installieren Sie Vue router und verwenden Sie: 🎜rrreee🎜Bearbeiten Sie die Router-Datei unter router/index.js
und aktualisieren Sie die Route, sodass die Funktion import()
anstelle von import
-Anweisung: 🎜🎜Die folgende Standardkonfiguration: 🎜rrreee🎜Ändern Sie sie in: 🎜rrreee🎜Wenn Sie die Option haben möchten, bestimmte Seiten bei Bedarf zu laden, anstatt den Vorabruf und das Vorladen global zu deaktivieren, können Sie diese verwenden Spezielle Webpack-Anmerkungen, Webpack nicht in vue.config.js
konfigurieren: 🎜rrreee🎜Der Hauptunterschied zwischen import()
und import
liegt bei Laufzeit: Laden Sie ES-Module, die von import()
geladen wurden, und laden Sie ES-Module, die von import
zur Kompilierungszeit geladen wurden. Das bedeutet, dass Sie mit import()
das Laden von Modulen verzögern und sie nur bei Bedarf laden können. 🎜🎜Einen Fortschrittsbalken implementieren🎜🎜Da es unmöglich ist, die Ladezeit (oder den vollständigen Ladevorgang) der Seite genau abzuschätzen, können wir wirklich keinen Fortschrittsbalken erstellen. Es gibt auch keine Möglichkeit zu überprüfen, wie viel die Seite geladen hat. Sie können jedoch einen Fortschrittsbalken erstellen und ihn beim Laden der Seite als abgeschlossen anzeigen lassen. 🎜🎜Da der Fortschritt nicht wirklich wiedergegeben werden kann, handelt es sich bei dem dargestellten Fortschritt nur um einen zufälligen Sprung. 🎜🎜Installieren Sie zuerst lodash.random
, da dieses Paket verwendet wird, um während des Prozesses der Generierung des Fortschrittsbalkens einige Zufallszahlen zu generieren: 🎜rrreee🎜Dann erstellen Sie eine Vue-Komponente components/ProgressBar .vue
: 🎜rrreee🎜 Als nächstes fügen Sie der Komponente ein Skript hinzu. Importieren Sie zunächst random
und $eventHub
in das Skript, die später verwendet werden: 🎜rrreee🎜Nach dem Import definieren Sie einige Variablen im Skript, die später verwendet werden: 🎜rrreee 🎜 Dann Code zum Implementieren der Logik des asynchronen Ladens von Komponenten: 🎜rrreee🎜Verwenden Sie in der Funktion montiert()
den Ereignisbus, um das Laden asynchroner Komponenten abzuhören. Sobald uns die Route mitteilt, dass wir zu einer Seite navigiert sind, die noch nicht geladen wurde, wird die Ladeanimation gestartet. 🎜🎜Fügen Sie zum Schluss etwas Stil hinzu: 🎜rrreee🎜Fügen Sie schließlich ProgressBar
zu App.vue
oder zur Layoutkomponente hinzu, sofern es sich in derselben Komponente wie die Routenansicht befindet ist während des gesamten Lebenszyklus der App verfügbar: 🎜rrreee🎜 Dann sehen Sie oben auf der Seite einen glatten Fortschrittsbalken: 🎜🎜🎜🎜Fortschrittsbalken für verzögertes Laden auslösen🎜🎜Jetzt überwacht ProgressBar
den Ereignisbus Hören Sie auf asynchrone Komponentenladeereignisse. Wenn bestimmte Ressourcen auf diese Weise geladen werden, soll eine Animation ausgelöst werden. Fügen Sie nun der Route einen Route-Daemon hinzu, um die folgenden Ereignisse zu empfangen: 🎜import $eventHub from '../components/eventHub' router.beforeEach((to, from, next) => { if (typeof to.matched[0]?.components.default === 'function') { $eventHub.$emit('asyncComponentLoading', to) // 启动进度条 } next() }) router.beforeResolve((to, from, next) => { $eventHub.$emit('asyncComponentLoaded') // 停止进度条 next() })
为了检测页面是否被延迟加载了,需要检查组件是不是被定义为动态导入的,也就是应该为 component:() => import('...')
而不是component:MyComponent
。
这是通过 typeof to.matched[0]?.components.default === 'function'
完成的。带有 import
语句的组件不会被归为函数。
在本文中,我们禁用了在 Vue 应用中的预取和预加载功能,并创建了一个进度条组件,该组件可显示以模拟加载页面时的实际进度。
原文:https://stackabuse.com/lazy-loading-routes-with-vue-router/
作者:Stack Abuse
相关推荐:
更多编程相关知识,请访问:编程入门!!
Das obige ist der detaillierte Inhalt vonImplementieren Sie Vue Lazy Loading mit Fortschrittsbalken. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!