小仙男·言在前
關于框架:為了解決VUE的SPA單頁應用對SEO搜索引擎優化不友好的問題,這幾天一直在調研各種SSR框架,比如doc.ssr-fc.com/ 和 fmfe.github.io/genesis-do 都是比較不錯,且有自己理念和想法的框架,但是對于公司來說技術規范差異太大,團隊學習成本比較高,思來想去,還是基于NUXT.JS自己搭建一套SSR框架慢慢完善吧,
關于本檔案:本檔案是從官網檔案中摘錄的一些重點內容,以及加入了自己的一些調整和對官網內容的理解和解釋,
關于官網:NUXT中文網 特別適合新手學習,檔案及案例十分清楚詳盡,可以說有手就行,但是,中文網的更新不及時,有些章節(比如fetch鉤子中不能使用this)甚至存在明顯錯誤,所以有一定技術水平的寶子,建議直接查看 NUXT英文官網 ,
【一、框架概述】
1、框架介紹
SSR技術(即服務端渲染技術),區別于原先純Vue框架的SPA應用(即單頁應用),SPA應用只有一個index.html的入口檔案,頁面顯示的所有內容均靠客戶端JS進行渲染,對于搜索引擎(SEO)優化來說,整個網站只有一個空頁面,十分不友好,而服務端渲染技術,是借助node.js作為框架服務端,在初次訪問一個頁面的時候,先在服務端預請求介面,并在服務端組裝完成的html頁面后,回傳給客戶端呈現,Nuxt.js是基于Vue框架的一款服務端渲染框架,提供了特有的框架結構和服務端渲染宣告周期,
2、開發環境
- 本框架基于
Node.js+Webpack+vue+Nuxt.js進行開發,提供ElementUI作為UI框架,開發前需全域安裝Node.js與webpack開發環境, - 框架推薦
Node.js版本為v16.15.0,最低版本不得低于12,推薦安裝nvm或n等node版本管理工具,
3、分支要求
- 遵循[前端團隊git倉庫及版本管理規范],即
master分支只用于拉取框架代碼,xxx_dev為開發分支,xxx_test為開發分支,xxx為生產分支,
3、關于本檔案
- 本檔案所述內容,已經是從官網中摘錄的【重中之重】,開發前請【詳盡】【仔細】【通讀】本檔案!!!尤其是【五、資料請求】 與 【六-8、重要Q&A】!!!
- 檔案描述存在錯誤的地方,請以【NUXT英文官網】為準,
【二、啟動與部署】
# 安裝框架以來
$ npm install
# 啟動本地開發環境,默認埠號:3000
$ npm run dev
# 編譯并在生產環境啟動
$ npm run build
$ npm run start
# 將網站打包成靜態化頁面
$ npm run generate
【三、框架結構】
- 詳細目錄結構介紹及使用,參照【六、其他規范與Q&A】
-- 框架根目錄
-- .nuxt Nuxt運營和編譯自動生成
-- dist 執行Nuxt靜態化時生成
-- api 全域通用的Api請求函式(非Nuxt提供)
-- assets 靜態資源目錄,存放全域css、image等
-- components 自定義組件目錄,此目錄下組件無需引入,按需使用即可
-- layout 布局檔案,參考https://www.nuxtjs.cn/guide/views
-- middleware 中間件,類似于路由守衛
-- modules 模塊,用于設定全域監聽等,參考https://www.nuxtjs.cn/guide/modules
-- pages 頁面目錄,Nuxt會根據此目錄自動生成路由,參考https://www.nuxtjs.cn/guide/routing
-- plugins 插件目錄,自定義各種插件,參考https://www.nuxtjs.cn/guide/plugins
> global.js (全域變數與全域方法)
> plugin.js (全域引入第三方組件)
> request.js (全域請求封裝)
> filter.js (全域過濾器封裝)
> util.js (全域工具函式封裝)
> all.client.js(僅在客戶端執行插件,暫時替代原app.vue)
-- static 不需要webpack編譯的靜態檔案,一般存放ico等檔案
-- store Vue狀態樹,與原寫法有所不同,參考https://www.nuxtjs.cn/guide/vuex-store
-- utils 工具類包 (非Nuxt提供)
.editorconfig
.gitignore
env.js 環境變數配置,分dev、test、pro三種環境
nux.config.js Nuxt的所有配置項,參考https://www.nuxtjs.cn/api/configuration-build
package-lock.json
package.json
README.md 框架使用檔案
ReleaseNote.md 版本更新說明
【四、生命周期】
-- Nuxt完整宣告周期
【服務端渲染】
-- 全域
nuxtServerInit 第一個:nuxt中第一個運行的生命周期
RouteMiddleware 第二個:中間件,類似于原框架的路由導航守衛
-- 組件
validate 是用來校驗url引數符不符合
asyncData Nuxt專屬宣告周期,可用于資料請求,只有page可用,子組件內部不可用
beforeCreate Vue宣告周期,但是服務端會執行(不可用于資料請求,資料請求相關操作會在客戶端執行)
created Vue宣告周期,但是服務端會執行(同上)
fetch Nuxt專屬宣告周期,可用于資料請求, page和子組件都可用
【客戶端渲染】
-- 全域
* `@/plugins/all.client.js` (并非Nuxt宣告周期,是只在客戶端運行的插件,此框架中用于暫時替代原框架中在App.vue中進行的全域初始化操作,)
-- 組件
beforeCreate
created
beforeMount
mounted
... (其他Vue后續宣告周期)
幾點說明:
beforeCreate/created是Vue的生命周期,但是會在服務端和客戶端各執行一次,但這兩個鉤子,僅供了解,不能用于資料請求,asyncData和fetch都是Nuxt提供的宣告周期,都可用于資料請求,只是寫法略有不同(參考后續章節【五、資料請求】),@/plugins/all.client.js并非Nuxt宣告周期,是只在客戶端運行的插件,但是Nuxt框架去掉了app.vue,此插件的宣告周期,近似于原來的app.vue,故暫時用于替代原框架中在App.vue中進行的全域初始化操作(是否恰當暫時不知),
【五、資料請求】
1. 資料請求鉤子
1.1 鉤子相關說明
asyncData和fetch都是Nuxt提供的宣告周期,都可用于資料請求,都會在服務端預請求資料進行組裝;asyncData只能在pages級別的頁面中呼叫,在子組件內部不能呼叫;fetch則可以同時在頁面和子組件中呼叫;- 官方建議資料請求均采用
asyncData,但為了保持與老框架寫法的一致,本框架暫時建議采用fetch(后果未知) fetch請求相比于asyncData的已知缺陷有:- ① 資料請求較慢,本框架Demo,從index頁進入Detail頁,當使用
fetch請求時,可明顯看到瀏覽器選項卡的title出現一瞬間undefined
- ① 資料請求較慢,本框架Demo,從index頁進入Detail頁,當使用
- 盡管
beforeCreate/created也可以在服務端渲染,但是這兩個鉤子的資料請求操作只會在客戶端執行,非特殊情況,切勿用于頁面初始化,
1.2 asyncData
- asyncData 中不能訪問this,但是可以在第一引數中,拿到context背景關系,使用context.app訪問Vue根示例;
- context背景關系還包含store、route、params、query等資料,詳見context背景關系
- asyncData中無法拿到組件實體,不能訪問組件實體中的data method等方法,
- 詳細介紹:asyncData
- 【請求示例】
// ① 使用return回傳的物件,將直接初始化到組件`data`中
async asyncData({app, params}) {
const { code, data } = await app.$get('/policy/findById/'+params.id)
return {detail: data}
},
// ② return一個Promise,將在Promise執行完成后,將資料初始化到組件`data`中
asyncData({app, params}) {
return app.$get('/policy/findById/'+params.id).then(res => {
return {detail: data}
})
},
// ③ 第二個引數為callback回呼函式,可直接傳入資料,初始化到組件`data`中
asyncData({app, params}, callback) {
app.$get('/policy/findById/'+params.id).then(res => {
callback(null, {detail: data})
})
},
1.3 fetch
- fetch 分兩種情況(新版本后支持第二種情況):
- ① 第一個引數接受context背景關系,則與asyncData一樣,不能訪問this和組件實體; (這種情況,也不支持像asyncData一樣通過return或者回呼函式修改data內容)
- ② 不接受任何引數時,則可以正常訪問this,(可以近似的看成created的用法,區別是 必須要使用await 或者return一個primary)
- 詳細介紹:fetch英文檔案 (中文檔案嚴重延遲,存在錯誤)
- 【請求示例】
// ① 使用return回傳一個Promise
fetch() {
return this.getDetail()
},
// ② 使用await/async
async fetch() {
await this.getDetail()
},
methods: {
// ① 使用await撰寫methods方法
async getDetail(id){
const { code, data } = await this.$get('/policy/findById/'+this.$route.params.id)
this.detail = data
}
// ② 使用return Promise撰寫methods方法
getDetail(id){
return this.$get('/policy/findById/'+this.$route.params.id).then(resw => {
this.detail = res.data
})
}
}
2. 資料請求方式
2.1 【框架推薦】 使用vue實體直接呼叫
- 本框架會將
$request/$get/$post掛在到vue根示例,建議直接只用this或背景關系context.app呼叫 - 【請求示例】
// 以this呼叫為例,如果是在`asyncData`中,需要使用背景關系`context.app`呼叫
// ① get
this.$get('/policy/findById/'+this.$route.params.id)
// ② post
this.$post('/policy/findAll/',{page:1,size:10,params:{}})
// ③ request
this.$request({
url: '/policy/findAll/',
method: 'post',
data: {page:1,size:10,params:{}}
})
2.2 兼容老框架的api分離式呼叫
- 本框架推薦使用
五 2.1的方式呼叫,但是也兼容了老框架的api分離式呼叫,用于提取可復用的公共請求, - 公共請求的api檔案,統一放在
@/api/*.js管理, - 【請求示例】
/**
* @/api/index.js
*/
import request from '@/utils/request'
export function getPageList(data) {
return request.post('/policy/findAll', data)
}
/**
* @/pages/index.vue
*/
import { getPageList } from "@/api/index.js"
export default {
fetch() {
return this.getPageList(this.pageDto)
},
methods: {
getPageList(pageDto) {
return getPageList(pageDto).then(res => {
this.pageList = res.data.result
})
}
},
}
3. 其他注意事項
- 原則上,所有初始化渲染資料的請求,都要在服務端渲染函式(
asyncData或fetch)中進行,極個別無法在服務端渲染的請求,可以在Vue的生命周期(created或mounted)中初始化; - 服務端渲染的生命周期(即
asyncData/fetch),不能使用任何瀏覽器專屬的對像(如DOM物件),也就是document和window,以及window的各種物件和方法,例如setTimeout、setInterval、localStorage、sessionStorage等;
有上述需求的初始化邏輯,可以放到created或mounted中初始化,
【六、其他規范與Q&A】
1. 關于pages
- 本框架路由采用
約定式路由,即不再使用route.js進行路由宣告,而是由框架根據pages目錄自動生成路由,詳見路由 - 檔案夾或者檔案,如果以
_開頭,表示此為動態路由,可以傳入不同引數,在組件內容,可以使用背景關系或者this.$router取到路由引數;- 例如:
/pages/news/detail/_id.vue、/pages/news/detail/_id/index.vue - 訪問:
http://domain.com/pages/news/detail/12345(上述兩種寫法均為這一路徑)
- 例如:
【注意】
- ① 使用
_id.vue的寫法,表示id為可選引數,即可以通過http://domain.com/pages/news/detail訪問,如果要對id進行限制或驗證,可以在組件內使用validate()驗證; - ② 使用
/_id/index.vue的寫法,表示id為必選引數,訪問http://domain.com/pages/news/detail會報404,如果只要求id必填,而沒有其他格式限制,可以使用此方式, - ③
validate()驗證示例
// return true表示驗證通過,return false表示驗證失敗 404
validate({ params }) {
return /^\d+$/.test(params.id)
},
2. 關于plugins
- 用于自定義框架所需的各種插件,宣告插件后在
nuxt.config.js中引入插件即可,類似于原框架main.js相關功能,詳見插件 - 框架已有的插件包(具體用戶參照各插件的
頂部注釋):plugin.js用于全域引入各種npm包;global.js用于宣告全域變數與全域方法;request.js實作了全域請求封裝(對應@/utils/request.js);filter.js實作了全域請求封裝(對應@/utils/filter.js);util.js實作了全域請求封裝(對應@/utils/util.js);all.client.js只在客戶端引入,用于替代原框架中app.vue中的各種初始化操作;
- 其他插件可根據需要自行定義,
*.js表示服務端客戶端均匯入;*.client.js表示僅在客戶端匯入;*.server.js表示只在服務端匯入;
3. 關于layout
- 用于定義框架中的各種布局檔案,可根據需要自行定義,詳見布局與視圖
- 默認視圖為
default.vue,默認所有頁面都將呼叫;error.vue是錯誤視圖,當頁面出現問題時,自動呼叫; - 其他視圖,可根據需要自行定義,并在組件內部宣告參考,
- 【組件呼叫示例】
export default {
// 需要呼叫的視圖名稱,不寫默認呼叫default.vue
layout: 'onlyBody',
data(){
return {}
}
}
4. 關于components
- 用于定義框架中的各種自定義組件,可根據需要自行定義,
- 自定義組件中的資料,一般應從頁面傳入,如果需要再組件內部獲取資料,應該使用
fetch(子組件中不支持asyncData), components中宣告的各種組件,在使用時,無需import匯入,直接使用組件名按需呼叫即可,- 【使用示例】
<template>
<div>
// Header組件
<Header />
</div>
</template>
5. 關于store
store檔案夾為Nuxt提供用于定義Vuex狀態樹的檔案夾,詳細檔案參照:Vuex狀態樹,- 此檔案夾下面的xxx.js,分別表示一個模塊,例如
index.js對應$store.state.xxx,而user.js對應$store.state.user.xxx - 本框架中
store中模塊的定義與普通Vue框架大體相同,只是Nuxt框架會自動參考Vuex并加載到構建配置重,無需我們自己new Vuex() - 【使用示例】
/**
* 【注意區別】
* state mutations action不再是包裹在一個物件中,并在new Vuex()的時候傳入, 而是分別作為單獨模塊使用export匯出即可,
*/
export const state = () => ({
counter: 0
})
export const mutations = {
increment(state) {
state.counter++
}
}
6. 關于middleware
middleware是框架中用于宣告中間件的檔案夾,宣告后在nuxt.config.js中配置中間件即可,詳細檔案參照:中間件,@/middleware/router.js為已經升級宣告好的路由守衛中間件,可替代原框架中router.beforeEach中的路由守衛功能;
7. 關于modules
- 用于自定義模塊的檔案夾,可以在模塊中對Nuxt啟動部署的各種宣告周期設定監聽,詳細檔案參照:模塊,
@/modules/generator.ts實作了一個對靜態化結束generate:done時進行監聽并處理的示例,
const generator: any = function () {
this.nuxt.hook('generate:done', (context: any) => {
// TODO samething
})
}
export default generator
- 類似
this.nuxt.hook('generate:done',() => {})的Nuxt框架hooks還有很多,例如:ready、error、render:before、build:compile等等……詳細參見INTERNALS
8. 其他Q&A
1)每個頁面,必須使用head設定title,必要時還需在詳情頁設定description,(!!!切記!!!)
export default {
head() {
return {
// title必須設定!!! 串列可以直接寫“xxx串列”,詳情頁等有不同標題的,要用新聞標題、商品標題等作為title前綴,
title: this.detail.title + '_新聞詳情',
meta: [
// 詳情頁,需要設定不同的description, this.$getDesc 為全域封裝的從富文本中截取100字符的description
{ hid: 'description', name: 'description', content: this.$getDesc(this.detail.details) },
],
}
}
}
2)pages目錄中的層級結構,務必按照功能梳理清楚,比如“news(新聞)”的串列、詳情都要在一個檔案夾中,
(!!!目錄結構一旦確定,原則上不可再調整!!!)
3)框架中的其他重要檔案之【CSS篇】!!
- 框架各種
css檔案,位于@/assets/css/中,框架推薦使用scss語言,使用"sass": "~1.32.13"進行編譯; common.scss為全域公共CSS,請將全域樣式表宣告于此,或自行定義CSS檔案,并在此檔案中import匯入;font.scss用于定義本框架各種字體、圖示庫等;variables.scss宣告了框架的各種全域Scss變數,可以在所有頁面使用,- 注意:全域主題色,請用
$mainColor表示,不要在各自檔案中自行宣告!
- 注意:全域主題色,請用
element-variables.scss是ElementUI的主題宣告檔案,如需全域調整ElementUI的配色,請在此調整;
4)(未完待續…)其他任何框架問題,詳詢小仙男
【本文作者】@小風飛魚【原文出處】http://www.cnblogs.com/qdjianghao/
【著作權宣告】本文著作權歸原作者@小風飛魚所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,
【聯系方式】1987289469
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/545813.html
標籤:其他
