iT邦幫忙

2021 iThome 鐵人賽

DAY 3
5
Modern Web

[ 重構倒數30天,你的網站不Vue白不Vue ] 系列 第 3

[重構倒數第28天] - 關於拆分 Components 的學問

  • 分享至 

  • xImage
  •  

前言

該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章,在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。

我要怎麼下第一刀?

很多人都會問我說,在寫 vue component 的時候,怎麼樣判斷這個東西要不要拆分成更細 component ? 或是當你接手人家的vue專案的時候,前人留下來的 component 有沒有必要在拆分呢?
mike

大部分的同學都會抱持者在繼續往下寫點東西再來決定的心態,然後就會造成 script、template、style 越寫越長,最後讓你的 component 變成一發不可收拾的地步...

先說結論

我們先不要管說這個元件是否會共用,單憑你的 component 裡面 script、template、style 加起來大約200 ~ 300行時,其實你就應該要先考慮切你的 component,再來談其他的共用 component 之類的...

我的專案 component 幾乎不會超過300行。

其原因有四:

  1. 當你的script、template、style加起來大約200 ~ 300行的時候,你的vue template語法以及你的script邏輯會綁再一起太多,而且加上控制畫面的 style的資料以及 css的結構會太複雜,當要改動起來是一件很費力的事情,由其實第一次看到這個component的時候會看的很辛苦。
  2. vue template 語法以及你的script邏輯會綁再一起太多的時候,這時候要再來切component會有點麻煩,畢竟全部寫在一起跟拆成component做資料傳遞上面,寫的邏輯就有點不一樣了。
  3. 可以減少動一髮牽動全身的狀況,當出現問題的時候可以更清楚找到問題點,對於資料傳遞的input、output也更加的明白。
  4. 很多時候我們在寫程式很容易把眾多邏輯跟寫在一起,造成難以維護以及閱讀的情況,適度的切component可以訓練你對於邏輯的拆解能力,降低各個邏輯的耦合性,減少邏輯之間的量子糾纏。

Component也有類別?

Vue 裡面我把 Component 分成三大類 Page components、Global components、UI components

  • Page components : 每個獨立頁面的 component,例如像是首頁、關於我們、產品列表等,都是一個獨立的頁面 component。

  • Global components : 網頁中你會有很多東西是在每個頁面都會出現,例如彈出視窗,或是你的 Header 或 Footer 組件等等這類型的 components。

  • UI components : 這個囊括了一般我們做元件拆分出來的 component 以及拆分 global components 裡面的內容,我都歸類在 UI components,只是一般頁面上用到的 component 不會被歸類在 global 之中。

為了讓大家更好理解,我們來看看以下設計稿
Vue3 Mike

我大概用以上三種分類的方式切分了一下component
Vue3 Mike

所以我們可以從這張圖很簡單的來清楚明瞭目前切的 component 是屬於哪個類別的。

在我們了解 component 是屬於哪個類別後我們就要對於專案之中 component 的擺放的資料夾開始去切分,我大概簡單的分類一下

|-- src
        |-- App.vue
        |-- main.js
        |-- api
        |   |-- index.js
        |-- assets
        |   |-- images
        |       |-- load.gif
        |       |-- logo.png
        |-- components
        |   |-- Global
        |   |   |-- Alert
        |   |   |   |-- index.vue
        |   |   |-- Footer
        |   |   |   |-- index.vue
        |   |   |-- Header
        |   |   |   |-- index.vue
        |   |   |-- Login
        |   |       |-- index.vue
        |   |-- Loading
        |   |   |-- CardLoading.vue
        |   |   |-- PageLoading.vue
        |   |-- Product
        |       |-- Card.vue
        |       |-- CardItem.vue
        |-- router
        |   |-- index.js
        |-- store
        |   |-- index.js
        |-- view
            |-- About.vue
            |-- Home.vue
            |-- News.vue
            |-- Product.vue

我會把 Page components 放入 view 的資料夾中,然後把 Global components、UI components 放入 components 的資料夾,然後把頁面自己的 component 放到該頁面的資料夾裡面再去做細分。

然後關於我們使用 component 這件事

我在載入的組件的時候會像這樣子

<script>
import { ref } from "vue";
import Dynamic from "@/components/Dynamic.vue";
export default {
  components: {
    Dynamic,
  },
  setup() {
    const isShow = ref(false);
    const Open = () => (isShow.value = true);
    return { isShow, Open };
  },
};
</script>

<template>
  <button id="show_btn" @click="Open">click</button>
  <Dynamic v-if="isShow" />
</template>

透過 import 載入 Dynamic.vue

import Dynamic from "@/components/Dynamic.vue";

然後再 components 裡面掛載 Dynamic 這個組件,然後放在 template,透過 v-if 來決定是否渲染出來,這樣基本上沒有什麼問題。

But...

就像上面這個範例一樣,我們網頁上面一開始的時候有些component是不想一開始就 show 出來的,所以會透過 v-if 來把它藏起來,不要讓使用者在開發者工具上面找到,但是這樣的載入方式會在網頁一開始載入資源的時候會一起把這個一開始不需要出現的 component 給也打包進來,當你的網頁越來越巨大的時候,這樣子的 component 會造成網站的載入負擔,那要怎麼解決這個問題呢?

我們可以透過 dynamic import 的方式來解決這個問題。

使用 dynamic import

<script>
import { defineAsyncComponent, ref } from "vue";
export default {
  components: {
    Dynamic: defineAsyncComponent(() => import("@/components/Dynamic.vue")),
  },
  setup() {
    const isShow = ref(false);
    const Open = () => (isShow.value = true);
    return { isShow, Open };
  },
};
</script>

<template>
  <button id="show_btn" @click="Open">click</button>
  <Dynamic v-if="isShow" />
</template>

我們可以透過import('@/components/Dynamic.vue')這樣的語法來讓我們的 component 變成動態載入的components,也就是說當我畫面上的 isShow 變成 true 的時候,我的 < Dynamic /> 的組件被渲染到網頁上面的時候,它才會載入這個資源,以減少一開始瀏覽器載入網頁資源的效率。

在 Vue3裡面如果你要使用 dynamic import 來載入 component 的話,你要用defineAsyncComponent 這個函式才可以使用dynamic import喔。
參考官方連結: https://v3.vuejs.org/guide/component-dynamic-async.html#async-components

我們可以來比較一下兩種載入方式的差異

.這是我們使用一般 import 的方式

Vue3 Mike

.這是我們使用 dynamic import 的方式

Vue3 mike

從這邊你就可以知道說使用 dynamic import 可以讓你在需要的時候在載入這個 component 就好了,不需要一開始的時候都載入,至於你要使用哪一種載入方式就依照你的頁面上面的邏輯再來決定你的 import 方式吧!

好啦! 今天介紹如何拆分 component 就到這邊啦,其實拆分 component 每個人的想法或許也都不太一下,我把過往工作上面拆分 component 的經驗分享出來給大家參考一下,希望有幫助到對於拆 component 有障礙的同學,如果有其他的拆分 component 有不一樣想法的朋友也歡迎底下留言一起討論。

Mike Vue

那如果對於Vue3不夠熟的話呢?

Ps. 購買的時候請登入或註冊該平台的會員,然後再使用下面連結進入網站點擊「立即購課」,這樣才可以讓我獲得更多的課程分潤,還可以幫助我完成更多豐富的內容給各位。

我有開設了一堂專門針對Vue3從零開始教學的課程,如果你覺得不錯的話,可以購買我課程來學習
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果對於JS基礎不熟的朋友,我也有開設JS的入門課程,可以參考這個課程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

訂閱Mike的頻道享受精彩的教學與分享

Mike 的 Youtube 頻道
Mike的medium
MIke 的官方 line 帳號,好友搜尋 @mike_cheng


上一篇
[重構倒數第29天] - Vue2 Option API 轉換 Vue3 Composition API
下一篇
[重構倒數第27天] - 在 Vue 各種 CSS 的引入使用
系列文
[ 重構倒數30天,你的網站不Vue白不Vue ] 32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
gior__ann
iT邦新手 2 級 ‧ 2021-09-03 13:07:35

學到了~ dynamic import
想請問老師 鐵人賽這些內容課程都會講到嗎?

Mike iT邦新手 3 級 ‧ 2021-09-03 13:51:24 檢舉

鐵人賽是課程的延伸喔,很多基礎的東西只有在課程裡面有

我要留言

立即登入留言