iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 21
1
Modern Web

RRR撞到不負責之 Laravel + Nuxt.js 踩坑全紀錄系列 第 21

Day 21. Nuxt page component 粉墨登場

  • 分享至 

  • twitterImage
  •  

Vue component 熟悉之後,今天要接著介紹 pages 底下的 Vue component 多了那些屬性以及相關介紹,為了避免混淆,以下稱為 page component!

新屬性導覽

export default {
    name: 'index',
    data() {
        return {};
    },
    // 新屬性:
    head () {
        return {};
    },
    loading: true,
    layout: 'ManagerLayout',
    transition: '',
    scrollToTop: false,
    middleware: 'ManagerAuth',
    validate (context) {
        return true;
    },
    async asyncData(context) {
        return {};
    },
    async fetch(context) {},
}
  • head:透過 vue-meta 設定頁面標頭相關資訊。

  • loading:設定 page component 載入的時候,是否要顯示載入進度條,或是在 nuxt.config.jsloading全局設定

  • layout:設定 page component 要套用 layouts 底下的哪個樣版,此屬性的設定值是 layout component 的檔案名稱。

  • transition:透過 <transition> 設定轉場和動畫效果。

  • scrollToTop:一般進入新頁面時,畫面會是置頂的,但如果是進入子頁面 (之後介紹的時候會進一步說明),畫面捲動的位置預設是會停留在當前的位置,因此如果希望一樣讓畫面回到最頂端可以將此屬性設為 true

  • middleware:載入 page component 之前會先經過設定的 middleware 的檢查,概念跟 Laravel 是差不多的。類似 layout,此屬性的設定值是 middlewares 底下的檔案名稱,若需要多個 middlewares 檢查則改用陣列,(官方有說設定值可以直接寫為 (async) function 形式,但建議還是統一管控比較好維護)。

  • validate:與 (async) function 形式的 middleware 極為相同,官網文件是用來檢查 URL 上的變數或是 vuex store 裡的資料,職責上類似 Laravel Route 的 where(),實際上要進行甚麼檢查都可以。

  • asyncData:最重要的屬性,主要串接 API 取得資料的地方,藉此才可以達到 SSR 的效果,同時對於回傳的物件內容會自動 mapping、覆蓋
    data 的回傳物件。

  • fetch:與 asyncData 幾乎一樣,只差在沒有回傳物件。官方文件是建議將要存入 vuex store 的資料在這裡取得,但實際上 asyncData 也做得到。

Nuxt Context

在 Nuxt 很多新屬性或是新功能都可以看到 function 的參數是帶入 context,它主要作用在 Nuxt 本身特殊的 lifecycle 上,而且通常看到 context 就代表該方法內無法透過 this 取得 Vue component 的資料。以就下列出數個 context 常用的屬性。

  • app:包含 Vue componnent 實例以及在 nuxt.config.js 中註冊的所有 SSR plugin。因此若要發送 request,可以使用 context.app.$axios

  • isClient:用來了解目前畫面是否由 client 渲染,已經被棄用,改用 process.client

  • isServer:用來了解目前畫面是否由 server 渲染,已經被棄用,改用 process.server

  • route:Vue Router route 的實例,同 Vue 的 this.$route

  • store:Vuex Store 的實例。

  • params:URL 中的變數資料,同於 this.$route.params

  • query:URL 中的 query string,同於 this.$route.query

  • redirect:用來跳轉網址的方法。

middleware

進入 page component 之前,會先透過給定的 middleware 檢查合法性,
實作步驟如下:

  1. middlewares 底下建立一個 .js 檔案,

  2. 開啟檔案並匯出預設 (async) function,function 內就是檢查、過濾的邏輯。由於沒有回傳值,所以如果不合法可以利用 context.redirect() 跳轉:

export default function (context) {
    let isValid = false;
    // ...
    if (!isValid) {
        // ...
        context.redirect('/login');
    }
}
  1. 將 page component 中的 middleware 設定為 .js 檔案名稱,例如 middleware 為 ManagerAuth.js 則設定如下:
export default {
    middleware: 'ManagerAuth',
}

Middleware 的設定除了在 page component,還有 layout component 以及 nuxt.config.jsrouter.middleware。如果是在 nuxt.config.js 設定,則每一次路由改變 (每次跳轉頁面) 都會被檢查一次,彼此之間的執行順序為:

  1. nuxt.config.js
  2. layout component
  3. page component

asyncData & fetch

兩者的用法很簡單且相似差別在於 asyncData 會回傳物件覆蓋 Vue component 的 data。

export default {
    async asyncData(context) {
        // 取得 ssr 需要渲染的資料
        return {
            // ...
        };
    },
    async fetch(context) {
        // 取得 ssr 需要渲染的資料
    }
}

這兩者大致可以整理出下面幾項重點:

  1. 會在 page component initialize 前呼叫
  2. 不能用 this 取得 Vue component 資料 (因為上一點)
  3. 兩者幾乎是同時觸發,可以視為兩條獨立的 thread 運作,執行順序不互相干擾:
const simulateAPI = (response, delay) => {
    return new Promise(resolve => {
        setTimeout(() => {
            const timestamp = new Date().getTime();
            response.timestamp = timestamp;
            resolve(response);
        }, delay);
    });
};

export default {
    async asyncData(context) {
        const allResponse = [];
        console.log(`asyncData 始於 ${new Date().getTime()}`);
        allResponse[0] = await simulateAPI({ id: 'asyncData-01' }, 1000);
        allResponse[1] = await simulateAPI({ id: 'asyncData-02' }, 3000);
        allResponse[2] = await simulateAPI({ id: 'asyncData-03' }, 2000);
        allResponse.forEach(element => {
            console.log(`${element.id}: ${element.timestamp}`);
        });
        console.log('---------------------------------');

        return {
            // ...
        };
    },
    async fetch(context) {
        const allResponse = [];
        console.log(`fetch 始於 ${new Date().getTime()}`);
        allResponse[0] = await simulateAPI({ id: 'fetch-01' }, 2000);
        allResponse[1] = await simulateAPI({ id: 'fetch-02' }, 2000);
        allResponse[2] = await simulateAPI({ id: 'fetch-03' }, 2000);
        allResponse.forEach(element => {
            console.log(`${element.id}: ${element.timestamp}`);
        });
        console.log('---------------------------------');
    }
}

https://ithelp.ithome.com.tw/upload/images/20190922/20112580O2F37Bssl7.png

從執行結果來看,asyncDatafetch 執行時間非常接近幾乎同時,進一步比較 asyncData-02 和 fetch-02,兩者除了起始時間差,基本上也是同時執行完畢,因此可以證明 asyncDatafetch 兩者的執行是獨立的。


在看過 Nuxt 在 page component 增加的一些新屬性及方法之後,明天則要介紹 pages 底下的目錄結構與 Nuxt 路由之間的關聯性以及如何製作動態路由!


上一篇
Day 20. 新鮮好吃的手做 v-model
下一篇
Day 22. 話說 Nuxt 的 VueRouter 呢?
系列文
RRR撞到不負責之 Laravel + Nuxt.js 踩坑全紀錄31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言