VUE SSR伺服器端渲染NUXT採坑總結
初始化建立專案
yarn create nuxt-app <專案名>
css預編譯
安裝 yarn add node-sass scss-loader sass-loader --save-dev
路由管理
在nuxt中路由已經被整合到框架中,所以不需要再單獨引入配置,而且當頁面檔案建立後, router會生成響應的路由,路由檔案在.nuxt/router.js檔案,用法上基本不變, 與vue-router用法不同部分記錄如下
跳轉與傳參
- nuxt路由跳轉同樣是分為兩種方式(宣告式和程式設計式),不同的是在nuxt中用跳轉標籤nuxt-link而不是router-link
- 傳參demo如下
1 <nuxt-link :to="{name:'home',params:{newsId:3306}}">home1</nuxt-link> 2 接收引數 3 asyncData({ params }) { 4 console.log('home1', params); 5 }, 6 <nuxt-link :to="{path:'home',query:{newsId:3306}}">home2</nuxt-link> 7 接收引數 8 asyncData({ query }) { 9 console.log('home2', query); 10 },
頁面切換動效
路由動效分為全域性動效和單獨頁面動效
- 建立動效檔案,在asset檔案下建立動效樣式檔案(這裡定義檔名changePage.css)
- 定義動畫效果,這裡定義簡單的淡入淡出效果
// 頁面預設的頁面切換類名為page-enter、page-enter-active、page-leave-active .page-enter-active, .page-leave-active { transition: opacity 1s; } .page-enter, .page-leave-active { opacity: 0; }
引入定義的動效檔案,在nuxt.config.js檔案中配置中引入該css檔案
定義單獨頁面動效
- 在頁面檔案中定義樣式類名
1 export default { 2 transition: 'home' 3 }
在css檔案中定義動畫效果
.home-enter-active, .home-leave-active { transition: all 2s; font-size: 12px; } .home-enter, .home-leave-active { opacity: 0; font-size: 40px; }
巢狀路由
開發業務中,有時難免會遇到需要二級甚至多層路由巢狀,官方文件中的二級路由介紹也是過於簡單,為此又多掉了幾根頭髮 這裡就拿官網文件的例子作為講解
1 第一:假設要建立一個user的二級路由,檔案結構如: 2 3 pages/ 4 --| users/ //2、最容易建立與user.vue檔案同名的資料夾,這樣nuxt就會識別出我們的意圖,原來是要建立巢狀路由 5 //假如資料夾與user.vue不同名,那麼該資料夾下的檔案同樣被生成一級路由 6 -----| _id.vue 7 -----| index.vue 8 --| users.vue // 1、首先要有user.vue檔案 9 10 第二:Nuxt.js 自動生成的路由配置如下: 11 router: { 12 routes: [ 13 { 14 path: '/users', 15 component: 'pages/users.vue', 16 children: [ 17 { 18 path: '', 19 component: 'pages/users/index.vue', 20 name: 'users' 21 }, 22 { 23 path: ':id', 24 component: 'pages/users/_id.vue', 25 name: 'users-id' 26 } 27 ] 28 } 29 ] 30 } 31 第三:在一級頁面中顯示二級頁面 32 <template> 33 <div class="page-me"> 34 <div>一級頁面的相關內容、、、</div> 35 <nuxt-child /> //二級頁面的檢視視窗,相當於Vue Router的<router-view></router-view> 36 </div> 37 </template>
路由攔截/鑑權
nuxt的路由攔截與Vue Router不同,需要引入中介軟體 的概念,好在文件介紹比較容易理解,現梳理如下
- 需要在指定的資料夾middleware/ 下建立路由攔截檔案(檔案不限數量)
- 一箇中間件接收 context 作為第一個引數,context包含了包括vuex等在內相關資料資訊,以此通過資料執行相關邏輯
export default function (context) { context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent }
在nuxt.config.js為全域性頁面定義路由攔截
module.exports = { router: { middleware: 'stats'//中介軟體檔名 } }
當然不想全域性定義路由攔截也可以為單獨的頁面定義路由攔截
//具體的頁面 export default { middleware: 'stats' }
錯誤頁設定
一個完成專案,404或其他錯誤頁面總是要有的,對此nuxt已經封裝了404頁面跳轉,在layouts資料夾下建立error.vue檔案(檔名必須是error.vue),元件接收error物件引數,通過引數的狀態碼判斷頁面錯誤原因
<template> <div class="container"> <h2 v-if="error.statusCode == 404">這是404頁面</h2> <h2 v-else>這是500頁面</h2> </div> </template> <script> export default { props: ['error'], //nuxt已經封裝好返回的 mounted() { console.log('error', this.error); } }; </script>
介面請求
安裝
- 安裝:yarn add @nuxtjs/axios
- 同正常的axios用法相同,不做詳細解釋
本地代理
- npm i @nuxtjs/proxy -D
- 在 nuxt.config.js 配置檔案中新增對應的模組,並設定代理
- 配置了代理,本地開發時axios就不能使用baseURL(打包時,baseURL還是需要放開)
1 modules: ['@nuxtjs/axios','@nuxtjs/proxy'], 2 axios: { 3 proxy: true 4 }, 5 proxy: {//代理可以設定多個 6 '/api': {// /api是指真實介面域名後的一個層級 7 target: 'http://example.com',//真實介面域名 8 pathRewrite: { 9 '^/api' : '/'// "/api"與上面的api相同 10 } 11 } 12 }
axios API封裝
- axios的封裝與常規vue專案相同,不同的區別是需要在配置檔案中將封裝檔案引入
plugins: ["@/plugins/element-ui", "~/plugins/api.js"]
api訪問本地開發
通過設定IP地址,這樣就可以通過IP訪問本地專案環境
//package.json中配置 "devDependencies": {}, "config": { "nuxt": { "host": "0.0.0.0", "port": "5000" } }
asyncData
用於服務端或路由更新之前被呼叫(如果這裡進行介面請求,頁面會等介面返回結果後才發生跳轉),方法的第一個引數被設定為當前頁面的上下文物件(即包含路由、引數等等的一些列資訊),可用於請求一個或多個介面,並將返回的資料融合到元件的data中,改方法與mounted函式同級,只在頁面模組的檔案內生效,在元件模組檔案內不生效,由於asyncData方法是在元件 初始化 前被呼叫的,所以在方法內是沒有辦法通過 this 來引用元件的例項物件。
寫法一 asyncData(context) { return ( axios.get('https://api.myjson.com/bins/8gdmr1').then(res => { return { info: res.data }; //注意,return返回的最好是key:value物件,直接return導致不利於從例項data中查詢使用,如: //return (res.data),因為沒有設定key,返回的資料雖然融合到例項的data上,但沒有key則沒法通過key值查詢使用 }), axios.get('https://api.myjson.com/bins/8gdmr').then(res => { return { info: res.data }; }) ); }, 寫法二 async asyncData({ params }) { const { data } = await axios.get('https://api.myjson.com/bins/8gdmr'); return { info: data }; },
Vuex
nuxt中集成了vuex,不需要新安裝外掛,Nuxt.js 會嘗試找到應用根目錄下的 store 目錄,並引用 vuex 模組,將 vuex 模組 加到 vendors 構建配置中去,設定 Vue 根例項的 store 配置項。
以上是官方文件原話,大白話翻譯就是:nuxt已經集成了vuex不需要手動安裝,nuxt會直接找到vuex檔案,並把vuex配置到專案中,然後就想正常vue一樣使用即可
建立與使用
- 1、vuex不需要新建立例項,即不需要new Vuex.Store({})
- 2、state的值應該始終是function,為了避免返回引用型別,會導致多個例項相互影響,即
//正確寫法 export const state = () => ({ counter: 0 }) //錯誤寫法 export const state = { counter: 0 }
資料持久化
為避免頁面重新整理資料狀態丟失,需要對vuex資料持久化,nuxt的vuex資料持久化與vue專案稍有不同,這裡推薦的是nuxt-vuex-localstorage
- 安裝
- 配置檔案引入
//nuxt.config檔案中引入 modules: ["nuxt-vuex-localstorage"]
歡迎大佬指教
專案中雖然在使用vuex,但遇到的問題依然很多,使用起來總是磕磕絆絆,歡迎留言指教
部分配置介紹
meta標籤設定
既然是為了SEO優化,那麼總是少不了mate標籤關鍵字設定,mate標籤分為定義全域性和單個頁面配置
- 配置檔案定義全域性
head: { title: process.env.npm_package_name || "", meta: [ { charset: "utf-8" }, { name: "viewport", content: "width=device-width, initial-scale=1" }, { hid: "description", name: "description", content: process.env.npm_package_description || "" } ], link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }] },
設定頁面獨有關鍵字
export default { data () { return { title: 'Hello World!' } }, head () { return { title: this.title, meta: [ { hid: 'description', name: 'description', content: 'My custom description' } ] } } }