非同步組件

by vivid 16. 十月 2019 11:32

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N191021202
出刊日期: 2019/10/16

當Vue應用程式為了提供新功能,不斷的成長,你就會開始意識到,該為應用程式調校效能了,如此方可讓它能夠更快的執行。非同步組件(Async Components)是這個問題的其中一種解法。有些組件並不是一開始就要呈現在網頁上,例如進度提示、對話盒等等,因此一開始將這些可能不需要呈現的組件載入並不是很有意義,在必要時再進行載入會比較理想,這種作法稱做延遲載入(Lazy Loading)。

雖然Vue支援非同步組件,但大部分的程式設計師並不曉得如何使用它們,在這篇文章中,將介紹非同步組件的使用與設計。

 

使用Vue CLI 建立專案

讓我們先利用Vue CLI 3.11版建立一個專案,了解一下預設使用靜態的方式來建立與使用組件。首先在作業系統命令提示視窗輸入使用以下指令,將專案命為「myasyncdemo」後按下「Enter」鍵:

vue create myasyncdemo

輸入上述指令之後,接下來會出現一些對話,詢問你是否使用預設的配置(preset),或者要手動進行設定,目前選擇使用預設的設定(default (babel, eslint)),預設選取「default」設定會加裝「babel」、「eslint」兩個插件(plugin),接下來按下「Enter」鍵,請參考下圖所示:

clip_image002

圖 1:建立專案

下一步便開始安裝相依插件(Plugin)相關檔案,這需要花費一些時間等待,這樣專案就建立完成了:

clip_image004

圖 2:安裝插件到專案。

依照命令提示字元視窗最後印出的指示,我們在命令提示視窗輸入以下指令,使用「cd」切換到「myasyncdemo」所在資料夾:

cd myasyncdemo

輸入以下指令,利用Visual Studio Code開發工具開啟專案:

code .

在開始進入到非同步組件的設計與使用之前,讓我們先來回顧一下,在Vue之中載入組件的標準作法。先在專案中「components」資料夾內加入一個「MyComponent.vue」組件,在組件檔案中,加入以下程式碼:

「MyComponent.vue」檔案程式列表

<template>
  <div >
     <h1> Hello My Component </h1>
  </div>
</template>

<script>
export default {
 
};
</script>

<style  scoped >
div {
  background-color: bisque;
}
</style>


修改「App.vue」檔案中的程式碼,加入以下程式碼,在「template」之中插入「<my-component/>」;在<script> 區段之中,利用「import」關鍵字匯入我們自訂的組件「MyComponent.vue」;利用「components」屬性註冊要使用的組件名稱「MyComponent」。這種載入方式我們稱之為靜態載入(Static Loading):

「App.vue」檔案程式列表

<template>
  <div id="app">
   <my-component/>
  </div>
</template>

<script>
import MyComponent from './components/MyComponent.vue'

export default {
  name: 'app',
  components: {
    MyComponent
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


在命令提示字元,或在Visual Studio Code開發工具輸入「CTRL + `」組合鍵開啟「TERMINAL」視窗輸入以下指令「npm run serve」,啟動開發階段網站伺服器:

npm run serve

開發階段的網站伺服器會動態賦予網站一個埠號,以本例來說,接聽在「8081」埠,請參考下圖所示:

clip_image006

圖 3:啟動開發階段網站伺服器。

開啟瀏覽器,根據上個步驟,輸入以下網址與埠號「http://localhost:8081/」,就可以看到網站最新首頁的內容,目前應用程式首頁的內容看起來如下圖所示:

clip_image008

圖 4:顯示組件資料。

當應用程式一開始執行時,便載入「App.vue」,而「App.vue」載入時,便會載入「MyComponent」,但這可能不是我們想要的,也許在需時使用它時,例如透過導覽選單,必要時再載入會是一個比較好的做法。

 

非同步載入(Async Loading)

Vue支援ES2018動態載入(Dynamic Import)的功能,可以在程式執行階段以非同步方式,動態載入模組(Module),以達到延遲載入(Lazy Loading)的目地。而Vue專案內建的「Webpack」模組打包器(Module Bundler)能夠自動識別這些語法,在必要時再載入模組。

你可以叫用「import」函式進行動態載入模組的動作,它會回傳一個「promise」物件,其中包含動態載入的模組。

讓我們來了解一下做法,「MyComponent.vue」檔案將會是我們要以非同步方式載入的組件,為了模擬下載一個大模組需要花費較久的時間,先修改「MyComponent.vue」檔案中的程式碼如下,其中「<p>」標籤之中加入了幾千行文字,節省文章的版面,省略不列出:

「MyComponent.vue」檔案程式列表

<template>
  <div >
     <h1> Hello My Component </h1>
     <p>
       Lorem ipsum dolor sit, amet consectetur adipisicing elit. <P> 標籤中裏頭有幾千行的文字字串,省略不印出
      </p>
  </div>
</template>

<script>
export default { };
</script>

<style  scoped >
div {
  background-color: bisque;
}
</style>

 

 

修改「App.vue」檔案程式碼如下,叫用「import」函式,載入「components」資料夾中的「MyComponent.vue」檔案:

「App.vue」檔案程式列表

<template>
  <div id="app">
   <my-component/>
  </div>
</template>

<script>

export default {
  name: 'app',
  components: {
    MyComponent : () => import("./components/MyComponent.vue")
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


「import」函式會回傳一個「promise」,我們使用箭頭函式「() => import("./components/MyComponent.vue")」註冊「MyComponent」,它會回傳一個組態物件。叫用「import」函式時,可以不指定模組的「.vue」副檔名,例如上個步驟程式可以改寫如下:

「App.vue」檔案程式列表

<template>
  <div id="app">
   <my-component/>
  </div>
</template>

<script>

export default {
  name: 'app',
  components: {
    MyComponent : () => import("./components/MyComponent ")
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


 

目前這個Vue應用程式範例的執行結果參考如下圖:

clip_image010

圖 5:範例測試結果。

使用loading組件

若非同步載入的組件檔案很小,在網路連線不差的環境下,馬上就可以呈現載入的組件。若要載入的組件檔案很大,例如我們目前的「MyComponent」組件,就算在本機進行測試也會覺得稍為卡頓個幾秒,才可以看到執行的結果。在這種情況下,大部分的網站程式會提供進度提示來告知使用者,載入的動作正在進行中,在Vue之中可以搭配loading組件來達到進度回饋的效果。

首先在專案「assets」資料夾之中加入一個用來進行進度回饋的動畫檔),「loading.gif」接著修改「components」資料夾中的「MyLoading.vue」檔案,這個檔案將會在載入「「MyComponent」組件」的過程中,顯示進度提示字串與動畫圖檔:

「components\MyLoading.vue」檔案程式列表

<template>
  <p>
    <img src="../assets/loading.gif" />
    <b>Loading ...</b>
  </p>
</template>
<style  scoped>
div {
  background-color: red;
}
img {
  width: 100px;
  height: 100px;
}
</style>

 

修改「App.vue」檔案中的程式碼,匯入「MyLoading」組件,並在註冊「MyComponent」組件時,額外設定「loading」、「delay」與「timeout」屬性:

「App.vue」檔案程式列表

<template>
  <div id="app">
   <my-component/>
  </div>
</template>

<script>
import MyLoading from "./components/MyLoading.vue";
export default {
  name: "app",
  components: {
    MyComponent: () => ({
      component: import("./components/MyComponent.vue"),
      loading: MyLoading,
      delay: 10,
      timeout: 2000
    })
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

 

「MyLoading.vue」檔案使用靜態載入的「import」語法匯入,因此切記,這個檔案要愈小愈好,才可以馬上載入顯示。此外我們還透過「delay」設定延遲10ms才顯示「MyLoading.vue」組件;而「timeout」屬性則用來設定逾期時間,若超過逾期時間還無法將「MyComponent」組件載入,那麼將會應用程式將會報錯。

目前這個Vue應用程式範例的執行結果參考如下圖,一開始執行時顯示「MyLoading.vue」組件:

clip_image012

圖 6:「MyLoading.vue」組件。

接著才會顯示「MyComponent」組件,請參考下圖所示:

clip_image014

圖 7:顯示組件資料。

使用error組件

前文提及,若超過逾期時間還無法將「MyComponent」組件載入,那麼將會應用程式將會報錯。我們可以提供自訂錯誤畫面,在發生錯誤時顯示以知會使用者。首先在「assets」資料夾加入「myerror.png」檔,用做在發生錯誤時要顯示的圖示。

在「components」資料夾中加入「MyError.vue」檔案,修改程式碼如下,自訂錯誤畫面:

「MyError.vue」檔案程式列表

<template>
  <p>
    <img src="../assets/myerror.png" />
    <b>Error Loading !!! </b>
  </p>
</template>
<style  scoped>
p {
  color : red;
}
img {
  width: 100px;
  height: 100px;
}
</style>

 

修改「App.vue」檔案,加入以下程式碼,匯入並註冊「MyError」組件,它將會在在入「MyComponent」組件失敗的情況下自動顯示,另外為了測試「MyError」組件,我們將「timeout」設為「0」使其一執行便發生錯誤:

「App.vue」檔案程式列表

<template>
  <div id="app">
   <my-component/>
  </div>
</template>

<script>
import MyLoading from "./components/MyLoading.vue";
import MyError from "./components/MyError.vue";

export default {
  name: "app",
  components: {
    MyComponent: () => ({
      component: import("./components/MyComponent.vue"),
      loading: MyLoading,
      error : MyError,
      delay: 5,
      timeout: 0
    })
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

 

目前這個Vue應用程式範例的執行結果參考如下圖:

clip_image016

圖 8:載入錯誤。

條件式載入

目前的範例雖然使用延遲載入的機制來載入「MyComponent」組件,不過因為在「App.vue」程式碼中直接使用到組件,因此它會在「App.vue」組件載入執行時,隨即載入「my-component」組件。

讓我們將它修改成必要時再進行載入,修改「App.vue」檔案,加入一個<button>,當按下這個按鈕時,會將「isLoad」屬性設定為「true」;而我們再利用「v-if」搭配「isLoad」,當「isLoad」為「true」的條件成立時,再載入「my-component」組件。

「App.vue」檔案程式列表

<template>
  <div id="app">
    <button @click="isLoad = true"> Load Component </button>
    <div v-if="isLoad" >
       <my-component />
    </div>
  </div>
</template>

<script>
import MyLoading from "./components/MyLoading.vue";
import MyError from "./components/MyError.vue";

export default {
  name: "app",
  data: () => {
    return { isLoad : false}
  },
  components: {
    MyComponent: () => ({
      component: import("./components/MyComponent"),
      loading: MyLoading,
      error : MyError,
      delay: 5,
      timeout: 3000
    })
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

 

目前這個Vue應用程式範例的執行結果參考如下圖:

clip_image018

圖 9:條件式載入。

按下「Load Component」按鈕後,才會載入並顯示「MyComponent」組件,請參考下圖所示:

clip_image020

圖 10:條件式載入。

Tags:

.NET Magazine國際中文電子雜誌 | VueJS | JavaScript | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List