Heim  >  Artikel  >  Web-Frontend  >  Implementieren Sie Vue Lazy Loading mit Fortschrittsbalken

Implementieren Sie Vue Lazy Loading mit Fortschrittsbalken

青灯夜游
青灯夜游nach vorne
2020-10-28 17:36:322543Durchsuche

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.

Implementieren Sie Vue Lazy Loading mit Fortschrittsbalken

Einführung

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 &#39;lodash.random&#39;
import $eventHub from &#39;../components/eventHub&#39;
</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 &#39;./components/ProgressBar.vue&#39;
export default {
       components: { ProgressBar },
}
</script>

然后你就可以在页面顶端看到一个流畅的进度条:

Implementieren Sie Vue Lazy Loading mit Fortschrittsbalken

为延迟加载触发进度条

现在 ProgressBar

Warum auf Abruf laden? 🎜🎜Die typische Funktionsweise von SPA in Vue.js besteht darin, alle Funktionen und Ressourcen zu packen und zusammen bereitzustellen, sodass Benutzer Ihre Anwendung verwenden können, ohne die Seite zu aktualisieren. Wenn Sie Ihre Anwendung nicht explizit so gestalten, dass Seiten bei Bedarf geladen werden, werden alle Seiten auf einmal geladen, oder es wird viel Speicher für unnötiges Vorladen verwendet. 🎜🎜Dies ist für große SPAs mit vielen Seiten sehr schädlich und führt zu einer schlechten Benutzererfahrung bei Verwendung von Mobiltelefonen der unteren Preisklasse und niedrigen Netzwerkgeschwindigkeiten. Beim On-Demand-Laden müssen Benutzer keine Ressourcen herunterladen, die sie derzeit nicht benötigen. 🎜🎜Vue.js bietet keine Ladeindikator-bezogenen Steuerelemente für dynamische Module. Selbst wenn Vorabruf und Vorladen durchgeführt werden, gibt es keinen entsprechenden Platz, um den Benutzer über den Ladevorgang zu informieren. Daher muss die Benutzererfahrung durch Hinzufügen eines Fortschrittsbalkens verbessert werden. 🎜🎜Vorbereiten des Projekts🎜🎜Zunächst benötigen Sie eine Möglichkeit für den Fortschrittsbalken, mit Vue Router zu kommunizieren. Der Ereignisbusmodus ist besser geeignet. 🎜🎜Der Event-Bus ist ein Singleton einer Vue-Instanz. Da alle Vue-Instanzen über ein Ereignissystem mit $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()
})
🎜Konfigurieren Sie dann Webpack so, dass das Vorabrufen und Vorladen deaktiviert ist, sodass Sie auf jede einzelne Funktion abzielen können Sie können dies einzeln deaktivieren, Sie können es aber auch global deaktivieren. Erstellen Sie eine 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: 🎜🎜Implementieren Sie Vue Lazy Loading mit 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

相关推荐:

2020年前端vue面试题大汇总(附答案)

vue教程推荐:2020最新的5个vue.js视频教程精选

更多编程相关知识,请访问:编程入门!!

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen