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.js
的 loading
中全局設定。
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 很多新屬性或是新功能都可以看到 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
:用來跳轉網址的方法。
進入 page component 之前,會先透過給定的 middleware 檢查合法性,
實作步驟如下:
在 middlewares
底下建立一個 .js
檔案,
開啟檔案並匯出預設 (async) function,function 內就是檢查、過濾的邏輯。由於沒有回傳值,所以如果不合法可以利用 context.redirect()
跳轉:
export default function (context) {
let isValid = false;
// ...
if (!isValid) {
// ...
context.redirect('/login');
}
}
middleware
設定為 .js
檔案名稱,例如 middleware 為 ManagerAuth.js
則設定如下:export default {
middleware: 'ManagerAuth',
}
Middleware 的設定除了在 page component,還有 layout component 以及 nuxt.config.js
的 router.middleware
。如果是在 nuxt.config.js
設定,則每一次路由改變 (每次跳轉頁面) 都會被檢查一次,彼此之間的執行順序為:
nuxt.config.js
兩者的用法很簡單且相似差別在於 asyncData
會回傳物件覆蓋 Vue component 的 data。
export default {
async asyncData(context) {
// 取得 ssr 需要渲染的資料
return {
// ...
};
},
async fetch(context) {
// 取得 ssr 需要渲染的資料
}
}
這兩者大致可以整理出下面幾項重點:
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('---------------------------------');
}
}
從執行結果來看,asyncData
和 fetch
執行時間非常接近幾乎同時,進一步比較 asyncData-02 和 fetch-02,兩者除了起始時間差,基本上也是同時執行完畢,因此可以證明 asyncData
與 fetch
兩者的執行是獨立的。
在看過 Nuxt 在 page component 增加的一些新屬性及方法之後,明天則要介紹 pages
底下的目錄結構與 Nuxt 路由之間的關聯性以及如何製作動態路由!