Vue
Nuxt
HiSKIO
所有畫面由前端 JS 操控:HTML 渲染,讀到 .js檔案 後再把相對應的 html 丟到畫面上。
只有一個頁面,用起來卻像 app 一樣。
右鍵 -> 檢視網頁原始碼 -> 內容幾乎是空的。
只更新部分畫面,而不是暴力的每次都砍掉重練。
所有畫面為伺服器端收到請求後,解析出完整的 HTML 後,再傳給使用者端。
綜合兩者 SSR + SPA:
第一個頁面由 Server side render,之後的操作還是由 Client side render
MVC 就是因為 code 變得越來越亂,所以將職責區分清楚的一種設計模式。SPA 就是因為想增進使用者體驗,而出現的一種在前端利用 Ajax 達成不換頁的方法。SSR 就是因為要解決 SPA 的 SEO 問題而出現的解法。
看使用情境決定決定使用哪種方式:
例如:音樂播放網站(不換頁)、後台系統網站(不需要 SEO),就適合使用 SPA;反之,產品網站(需要 SEO),較適合使用 SSR。
詳見官網介紹:Nuxt.js - The Intuitive Vue Framework
Nuxt.js 是一個基於 Vue.js 的通用應用框架。
nuxt generate
,為基於 Vue.js 的應用提供生成對應的靜態站點的功能。Nuxt.js 是建構在 Node.js 環境之上。
Nuxt 將專案打包成兩份,一份是給 Client 端,一份是給 Server 端。
npx create-nuxt-app <project-name>
npm:是套件管理工具,可以把想要的 node 套件,透過 npm 安裝在 local 專案位置或是 global 全局性整台電腦的環境下。
npx:npx 是在 npm v5.2.0 之後內建的指令,也是一種安裝工具,讓我們可以更方便的安裝或是管理依賴(dependencies)。
主要特點:
參考資料:
.vue
檔router
。<Nuxt />
即為 pages
中的 .vue
檔內容 (很像 Vue CLI 中的 router-view
)
<template>
<div>
<TheHeader />
<Nuxt />
<TheFooter />
</div>
</template>
例如:
layouts/blog.vue
<template>
<div>
<div>My blog navigation bar here</div>
<Nuxt />
</div>
</template>
在 pages
component 中指定要呈現的 layouts
pages/posts.vue
<script>
export default {
layout: 'blog',
// OR
layout (context) {
return 'blog'
}
}
</script>
當有錯誤(e.g. 404, 500)發生時呈現的頁面。
雖然該檔案位於 layouts
之下,但屬於 pages
components!
因此不會有 <Nuxt />
在其中。
layouts/error.vue
<template>
<div class="container">
<h1 v-if="error.statusCode === 404">Page not found</h1>
<h1 v-else>An error occurred</h1>
<NuxtLink to="/">Home page</NuxtLink>
</div>
</template>
<script>
export default {
props: ['error'],
layout: 'blog' // you can set a custom layout for the error page
}
</script>
v2.13,
以後可以自動引入進任何 pages
,layouts
或 components
中,無需手動 import。在 nuxt.config.js
中設定:
export default {
components: true
}
詳細設定請見官網
動態載入即所謂的懶加載。只要在 template 中加入 Lazy
前綴詞。
layouts/default.vue
<template>
<div>
<TheHeader />
<Nuxt />
<LazyTheFooter />
</div>
</template>
當事件被觸發時,動態載入元件。
pages/index.vue
<template>
<div>
<h1>Mountains</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Show List</button>
</div>
</template>
<script>
export default {
data() {
return {
show: false
}
}
}
</script>
若元件放置位置如下:
components/
base/
foo/
Button.vue
則該元件的名稱則包含其路徑位置,即為 <BaseFooButton />
。
若不想包含特定路徑在元件名稱中,則需要在 nuxt.config.js
中指明:
components: {
dirs: [
'~/components',
'~/components/base'
]
}
則原本的 <BaseFooButton />
就可以改成 <FooButton />
。
assets
: 會經過 Nuxt
編譯壓縮打包。例如:第三方套件的 css 檔。static
: 不會經過 Nuxt
編譯壓縮打包。例如:json 檔。middleware
: 進入頁面前需要處理的事。例如:驗證。store
: 放 Vuex
的資料。plugins
: 自定義 Nuxt
的套件。從 nuxt.config.js
中做引入,供全局環境使用。asyncData
v.s. fetch
asyncData
頁面被渲染以前,在 server 端執行的生命週期函式。
例如:非同步處理,做 SEO。
asyncData
只會執行一次!asyncData
只能在 pages
資料夾底下的 .vue
中使用!asyncData
return 的值會覆蓋掉 data
中取相同名稱的值。可以直接 return 值到 template。this
! (this
是指 Vue 實體)fetch
只能在 Nuxt 2.12 之後的版本使用。
頁面被渲染以前,在 server 端及 client 端執行的生命週期函式。
與 asyncData
不同的地方:
pages
資料夾)。this
。因為在 created
之後,Vue 的實體就會被 new 出來。提供 $fetchState
在非同步資料取得時使用
$fetchState.pending
: Boolean
。讓你在 client 端判斷 fetch
執行完沒。可以在 pending 為 true 時,放 loading 的顯示。<div v-if="$fetchState.pending">Loading...</div>
$fetchState.error
: null
or Error ({Obj})
。判斷 fetch
是否執行出錯,可將 Error 呈現出來。<div v-if="$fetchState.error">Error {{ $fetchState.error }}</div>
$fetchState.timestamp
: Integer
。最後一次執行 fetch
的時間。適合與 keep-alive
的暫存功能搭配使用。keep-alive
keep-alive
可以保存已造訪過頁面的 fetch
執行結果。
在 <Nuxt />
或 <NuxtChild />
中加入 keep-alive
指令。
<template>
<Nuxt keep-alive />
</template>
可以使用 keep-alive-props
來指定要傳入的 props
<template>
<Nuxt keep-alive :keep-alive-props="{ max: 10 }" />
</template>
activated
生命週期只有在距上次呼叫 fetch
後的 30 秒,才會再次執行 fetch
。
使用 this.$fetch()
可手動執行 fetch
生命週期。
<template> ... </template>
<script>
export default {
data() {
return {
posts: []
}
},
activated() {
// Call fetch again if last fetch more than 30 sec ago
if (this.$fetchState.timestamp <= Date.now() - 30000) {
this.$fetch()
}
},
async fetch() {
this.posts = await fetch('https://api.nuxtjs.dev/posts').then(res =>
res.json()
)
}
}
</script>
fetchOnServer
: Boolean
or Function
(預設為 true)若 fetchOnServer
: false,則 fetch
只會在 client 端執行。
export default {
data() {
return {
posts: []
}
},
async fetch() {
this.posts = await fetch('https://api.nuxtjs.dev/posts').then(res =>
res.json()
)
},
// call fetch only on client-side
fetchOnServer: false
}
$route.query
當 router 的 query string 改變時,是不會執行 fetch
生命週期。可以使用 watch
進行監聽。
export default {
watch: {
'$route.query': '$fetch'
},
async fetch() {
// Called also on query changes
}
}
beforeCreate
& created
beforeCreate
與 created
在 server 端與 client 端都會被執行。
export default {
asyncData () {
console.log('asyncData')
},
beforeCreate () {
console.log('beforeCreate')
},
created () {
console.log('created')
},
fetch () {
console.log('fetch')
},
beforeMount () {
console.log('beforeMount')
},
mounted () {
console.log('mounted')
}
}