以前一直都是作vue-spa單頁面,不利於SEO。而便於SEO的SSR(服務器端渲染)多頁應用,可使用nuxt.js這個框架來實現css
(0)nuxt安裝 npx create-nuxt-app <項目名> 如下是按生成的目錄文件進行學習瞭解 (1)資源目錄assets 與 static目錄 - 資源文件部分 assets:靜態資源文件被 Webpack 作構建編譯處理 《1》css文件中引入資源 //注意~後無斜槓 background:url("~assets/banner.svg") 《2》vue文件中: <img src="~/assets/image.png"> static:無需Webpack編譯處理 資源相對路徑來解決路徑問題 《1》vue文件中 <img src="../static/1.png"/> (2)佈局目錄layouts / 頁面pages - 視圖部分 《1》默認佈局(layouts/default.vue) <template> <nuxt/> </template> 《2》自定義佈局 1.建立文件layouts/self.vue <template> <div> <div>自定義佈局</div> <nuxt/> </div> </template> 2.頁面中使用pages/index export default { layout: 'self' //指定自定義模板 } 《3》錯誤頁面 定製化錯誤頁面:.layouts/error.vue <template> <div class="container"> <h1 v-if="error.statusCode === 404">頁面不存在</h1> <h1 v-else>應用發生錯誤異常</h1> <nuxt-link to="/">首 頁</nuxt-link> </div> </template> <script> export default { props: ['error'], layout: 'self' // 你能夠爲錯誤頁面指定自定義的佈局 } </script> 《4》pages頁面配置項: asyncData、fetch、head、layout、loading、transition、scrollToTop、validate、middleware 此部分查看Api - 頁面部分 (3)插件目錄plugins(全局配置)- 插件部分 《1》使用插件 a.plugins/vue-notifications.js import Vue from 'vue' import VueNotifications from 'vue-notifications' Vue.use(VueNotifications) b.nuxt.config.js內配置 module.exports = { plugins: ['~/plugins/vue-notifications'] } 《2》注入Vue 實例 a.plugins/vue-inject.js: import Vue from 'vue' Vue.prototype.$myInjectedFunction = (string) => console.log("This is an example", string) b.nuxt.config.js export default { plugins: ['~/plugins/vue-inject.js'] } c.pages頁面使用: this.$myInjectedFunction('test') 《4》注入context a.plugins/ctx-inject.js: export default ({ app }, inject) => { // Set the function directly on the context.app object app.myInjectedFunction = (string) => console.log('Okay, another function', string) } b.nuxt.config.js: export default { plugins: ['~/plugins/ctx-inject.js'] } c.pages頁面使用: export default { asyncData(context){ context.app.myInjectedFunction('ctx!') } } 《5》同時注入 - inject方法 a.plugins/combined-inject.js export default ({ app }, inject) => { inject('myInjectedFunction', (string) => console.log('That was easy!', string)) } b.調用以上兩種方式都行 《6》只在客戶端使用的插件nuxt.config.js export default { plugins: [ { src: '~/plugins/both-sides.js' }, //both client & server { src: '~/plugins/client-only.js', mode: 'client' }, { src: '~/plugins/server-only.js', mode: 'server' } ] } (4)路由部分: 依據 pages 目錄結構自動生成 vue-router 模塊的路由配置 (1)動態路由: pages/ --| _slug/ -----| comments.vue -----| index.vue --| users/ -----| _id.vue --| index.vue router: { routes: [ { name: 'index', path: '/', component: 'pages/index.vue' }, { name: 'users-id', path: '/users/:id?', component: 'pages/users/_id.vue' }, { name: 'slug', path: '/:slug', component: 'pages/_slug/index.vue' }, { name: 'slug-comments', path: '/:slug/comments', component: 'pages/_slug/comments.vue' } ] } 路由參數校驗:pages/users/_id.vue validate ({ params }) { // 必須是number類型 return /^\d+$/.test(params.id) } (2)嵌套路由 注意: 1.添加一個 Vue 文件,同時添加一個與【該文件同名的目錄】用來存放子視圖組件。 2.別忘了在父組件(.vue文件) 內增長 <nuxt-child/> 用於顯示子視圖內容。 pages/ --| users/ -----| _id.vue -----| index.vue --| users.vue router: { routes: [ { path: '/users', component: 'pages/users.vue', children: [ { path: '', component: 'pages/users/index.vue', name: 'users' }, { path: ':id', component: 'pages/users/_id.vue', name: 'users-id' } ] } ] } (5).中間件目錄middleware - 用於存放應用的中間件 注意: 1.中間件容許您定義一個自定義函數運行在一個頁面或一組頁面渲染以前(相似vue-router導航守衛) 2.文件名的名稱將成爲中間件名稱(middleware/auth.js將成爲 auth 中間件) 3.一箇中間件接收 context 做爲第一個參數 (context - 見APi) export default function (context) { context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent } 4.中間件執行流程順序:nuxt.config.js -> 匹配佈局 -> 匹配頁面 5.案例: 1.middleware/stats.js import axios from 'axios' export default function ({ route }) { return axios.post('http://my-stats-api.com', { url: route.fullPath }) } 2.在nuxt.config.js 、 layouts 或者 pages 中使用中間件 (1)nuxt.config.js:在每一個路由改變時被調用 module.exports = { router: { middleware: 'stats' } } (2)layouts/default.vue 或者 pages/index.vue export default { middleware: 'stats' } (6)Store 目錄 - Vuex 狀態樹
1.store/index.js 跟其餘方式沒啥差異
2.模塊化使用場景一:
store/
--| todos/ (文件夾模塊,文件名爲對應store屬性名)
-----| state.js
-----| getters.js
-----| mutations.js
-----| actions.js
頁面使用:
import { mapMutations, mapGetters } from 'vuex'
...mapMutations({toggle: '模塊名/對應方法名'})
例子:
...mapMutations({toggle: 'todos/test'})
this.$store.commit('todos/test', { 參數 })
3.模塊化使用場景二:
store/
--| articles/ (文件夾模塊)
-----| comments.js
--| articles.js (根目錄文件模塊)
頁面使用:
import { mapGetters } from 'vuex'
...mapGetters({
articles: 'articles/get', //根目錄文件模塊
comments: 'articles/comments/get' //文件夾模塊
})html
(7)異步數據(asyncData) 1.限於頁面組件 - 每次加載以前被調用(beforeCreate以前執行) 2.因爲asyncData方法是在組件 初始化 前被調用的,因此在方法內是沒有辦法經過 this 來引用組件的實例對象。 2.第一個參數被設定爲當前頁面的上下文對象:即參數爲對象context,對象屬性: https://zh.nuxtjs.org/api/context context:{ app: Vue 根實例 //context.app.$axios, params:route.params 的別名, query:route.query 的別名, error:展現錯誤頁, redirect:重定向用戶請求到另外一個路由,redirect([status,] path [, query]) env:nuxt.config.js 中配置的環境變量,見 環境變量 api(嵌套路由例子-見demo) store:Vuex 數據, route:Vue Router 路由實例, isDev:開發 dev 模式, isHMR:模塊熱替換, req: res: nuxtState: beforeNuxtRender(fn): } 使用回調/動態路由參數/錯誤處理: 使用配置它的文件或文件夾的名稱訪問動態路徑參數:_id.vue export default { asyncData ({ params }, callback) { axios.get(`https://my-api/posts/${params.id}`) .then((res) => { callback(null, { title: res.data.title }) }).catch((e) => { //statusCode: 指定服務端返回的請求狀態碼 error({ statusCode: 404, message: 'Post not found' }) }) } } 獲取query參數 https://zh.nuxtjs.org/api/pages-watchquery watchQuery: ['page'] 若是定義的字符串發生變化,將調用全部組件方法(asyncData, fetch, validate, layout, ...) 《8》過渡動效 1.全局過渡動效設置 Nuxt.js 默認使用的過渡效果名稱爲 page 例子: //assets/main.css .page-enter-active, .page-leave-active { transition: opacity .5s; } .page-enter, .page-leave-active { opacity: 0; } //nuxt.config.js module.exports = { css: [ 'assets/main.css' ] } //使用 自動全局使用 2.頁面過渡動效設置 頁面樣式: .bounce-enter-active { animation: bounce-in .8s; } .bounce-leave-active { animation: bounce-out .5s; } @keyframes bounce-in { 0% {transform: scale(0)} 50% { transform: scale(1.5) } 100% { transform: scale(1) } } @keyframes bounce-out { 0% { transform: scale(1) } 50% { transform: scale(1.5) } 100% { transform: scale(0) } } 頁面運用: export default { transition: 'bounce', //動畫 } 或者: export default { transition: { name: 'test', mode: 'out-in' } } 3.transition爲函數類型時運用 見demo案例 <template> <div class="container"> <NuxtLink v-if="page > 1" :to="'?page=' + (page - 1)">< Prev</NuxtLink> <a v-else class="disabled">< Prev</a> <span>{{ page }}/{{ totalPages }}</span> <NuxtLink v-if="page < totalPages" :to="'?page=' + (page + 1)">Next ></NuxtLink> <a v-else class="disabled">Next ></a> <ul> <li v-for="user in users" :key="user.id"> <img :src="user.avatar" class="avatar" /> <span>{{ user.first_name }} {{ user.last_name }}</span> </li> </ul> </div> </template> <script> export default { // Watch for $route.query.page to call Component methods (asyncData, fetch, validate, layout, etc.) watchQuery: ['page'], // Key for <NuxtChild> (transitions) key: to => to.fullPath, // Called to know which transition to apply transition (to, from) { if (!from) { return 'slide-left' } return +to.query.page < +from.query.page ? 'slide-right' : 'slide-left' }, async asyncData ({ query }) { const page = +query.page || 1 const data = await fetch(`https://reqres.in/api/users?page=${page}`).then(res => res.json()) return { page: +data.page, totalPages: data.total_pages, users: data.data } } } </script> (9)自定義加載 第一種:自定義加載組件 1.components/loading loading.vue 2.nuxt.config.js loading: '~/components/loading.vue' 第二種:加載進度條 1.nuxt.config.js loading: { color: 'red' } //修改進度條樣式 2.pages/index 頁面中 this.$nuxt.$loading.start() //啓動加載條 this.$nuxt.$loading.finish() //介乎加載條 (10)其餘: process.static:是否爲true來判斷應用是否經過nuxt generator生成 process.server:當值爲 true 表示是當前執行環境爲服務器中 控制插件中的某些腳本庫只在服務端使用 案例:process.static ? 'static' : (process.server ? 'server' : 'client')