下面Vue.js欄位為大家介紹一下為Vue的惰性載入新增進度條的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

簡介
通常用Vue.js 寫單頁應用程式(SPA)時,當載入頁面時,所有必要的資源(如JavaScript 和CSS文件)都會一起載入。在處理大文件時,這可能會導致用戶體驗不佳。
借助 Webpack,可以用 import()
函數而不是 import
關鍵字在 Vue.js 中按需載入頁面。
為什麼要按需載入?
Vue.js 中 SPA 的典型運作方式是將所有功能和資源打包一併交付,這樣可以使用戶無需刷新頁面即可使用你的應用程式。如果你沒有為了按需加載頁面針對自己的應用進行明確的設計,那麼所有的頁面會被立即加載,或者提前使用大量內存進行不必要的預加載。
這對有許多頁面的大型 SPA 非常不利,會導致使用低階手機和低網路速度的使用者體驗會很差。如果透過按需加載,用戶將不需要下載他們目前不需要的資源。
Vue.js 沒有為動態模組提供任何載入指示器相關的控制項。即使進行了預取和預加載,也沒有對應的空間讓用戶知道加載的過程,所以還需要透過添加進度條來改善用戶體驗。
準備專案
首先需要一種讓進度條與 Vue Router 通訊的方法。 事件總線模式比較適合。
事件匯流排是一個 Vue 實例的單一範例。由於所有 Vue 實例都有一個使用 $on
和 $emit
的事件系統,因此可以用它在應用程式中的任何地方傳遞事件。
首先在components
目錄中建立一個新檔案eventHub.js
:
1 2 | import Vue from 'vue'
export default new Vue()
|
登入後複製
然後把Webpack 配置為停用預取和預先加載,這樣就可以針對每個函數單獨執行此類操作,當然你也可以全域停用它。在根資料夾中建立一個vue.config.js
檔案並新增禁用預取和預先載入的相關設定:
1 2 3 4 5 6 7 | module.exports = {
chainWebpack: (config) => {
config.plugins. delete ( 'prefetch' )
config.plugins. delete ( 'preload' )
},
}
|
登入後複製
新增路由和頁面
用npx
安裝Vue router 並使用:
編輯位於router/index.js
下的router 檔案並更新路由,以便可以用import()
函數取代import
語句:
以下預設配置:
1 2 3 4 5 6 | import About from '../views/About.vue'
{
path: '/about' ,
name: 'About' ,
component: About
},
|
登入後複製
將其改為:
1 2 3 4 5 | {
path: '/about' ,
name: 'About' ,
component: () => import( '../views/About.vue' )
},
|
登入後複製
如果希望可以選擇按需載入某有些頁面,而不是全域停用預取和預先加載,可以用特殊的Webpack 註釋,不要在vue.config.js
中設定Webpack:
1 2 3 4 5 | import(
'../views/About.vue'
)
|
登入後複製
import()
和import
之間的主要差異是在執行時間載入由import()
載入的ES 模組,在編譯時載入由import
載入的ES 模組。這意味著可以用 import()
延遲模組的加載,並僅在必要時加載。
實作進度條
由於無法準確估算頁面的載入時間(或完全載入),因此我們無法真正的去建立進度列。也沒有辦法檢查頁面已經載入了多少。不過可以建立一個進度條,並使它在頁面載入時完成。
由於無法真正反映進度,所以描繪的進度只是進行了隨機跳躍。
先安裝lodash.random
,因為在產生進度條的過程中將會用這個套件產生一些隨機數字:
然後,建立一個Vue 元件components/ProgressBar.vue
:
1 2 3 4 5 6 7 8 9 10 | <template>
<p>
</p>
<p>
</p>
<p></p>
<p></p>
</template>
|
登入後複製
接下來向該元件新增腳本。在腳本中先導入random
和$eventHub
,後面會用到:
1 2 3 4 | <script>
import random from 'lodash.random'
import $eventHub from '../components/eventHub'
</script>
|
登入後複製
導入之後,在腳本中定義一些後面要用到的變數:
1 2 3 4 5 6 7 8 9 10 | const defaultDuration = 8000
const defaultInterval = 1000
const variation = 0.5
const startingPoint = 0
const endingPoint = 90
|
登入後複製
接著編碼實作非同步載入元件的邏輯:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | export default {
name: 'ProgressBar' ,
data: () => ({
isLoading: true,
isVisible: false,
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()
函數中,用事件匯流排來偵聽非同步元件的載入。一旦路由告訴我們已經導航到尚未載入的頁面,它將開始載入動畫。
最後其添加一些樣式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <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
或佈局元件中,只要它與路由視圖位於在同一元件中即可,它在應用的整個生命週期中都可用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <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
正在事件總線上偵聽非同步元件載入事件。當某些資源以這種方式加載時應該觸發動畫。現在為路由新增一個路由守護來接收以下事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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视频教程精选
更多编程相关知识,请访问:编程入门!!
以上是實作帶有進度條的Vue延遲載入的詳細內容。更多資訊請關注PHP中文網其他相關文章!