Nuxt.js實戰(zhàn)詳解
一、為什么選擇Nuxt.js
多數是基于webpack構建的項目,編譯出來的html文件,資源文件都被打包到js中,以下圖404頁面代碼為例。從代碼中可以看出,這樣的頁面是不利于 搜索引擎優(yōu)化(SEO, Search Engine Optimization) ,并且 內容到達時間(time-to-content) (或稱之為首屏渲染時長)也有很大的優(yōu)化空間。為了解決以上問題,引入了 Nuxt.js 框架。
vue官網對于Nuxt.js也是很推薦的,除此之外,Nuxt.js的開發(fā)者積極活躍,版本迭代迅速。經過一系列rc版本后,終于在1月9日發(fā)布了 v1.0.0 正式版本!
圖1. 使用webpack構建的HTML(代碼已格式化)
圖2. 使用 Nuxt.js 構建的HTML(代碼已格式化)
二、Nuxt.js 簡介
Nuxt.js 是一個基于 Vue.js 的通用應用框架,它預設了利用 Vue.js 開發(fā) 服務端渲染(SSR, Server Side Render) 的應用所需要的各種配置,同時也可以一鍵生成靜態(tài)站點。
作為框架,Nuxt.js 為 客戶端/服務端 這種典型的應用架構模式提供了許多有用的特性,例如異步數據加載、中間件支持、布局支持等。區(qū)別于其他 vue SSR 框架,Nuxt.js 有以下比較明顯的特性。
- 自動代碼分層
- 強大的路由功能,支持異步數據(路由無需額外配置)
- HTML頭部標簽管理(依賴 vue-meta 實現)
- 內置 webpack 配置,無需額外配置
三、項目實戰(zhàn)1、項目創(chuàng)建
官方提供了基于 vue-cli 腳手架工具,常用的有如下三個,更多腳手架工具可以查看nuxt-community 。本項目使用的是 express-template。
vue init nuxt-community/starter-template <project-name> vue init nuxt-community/koa-template <project-name> vue init nuxt-community/express-template <project-name>
2、開發(fā)
1)目錄結構
├─assets 資源目錄,未編譯的靜態(tài)資源如less、js ├─components 組件目錄 ├─layouts 布局目錄 ├─mock mock數據 ├─node_modules ├─pages 頁面目錄 ├─index.vue ├─.... ├─plugins 插件 ├─server express服務 ├─static 靜態(tài)文件目錄 ├─store vuex store ├─utils 工具方法
2)配置
Nuxt.js 默認的配置涵蓋了大部分使用情形,也可通過修改 nuxt.config.js
來覆蓋默認配置。
// nuxt.config.js 文件配置 const path = require('path') module.exports = { // Headers of the page head: { title: '默認共用title', meta: [ { charset: 'utf-8' }, { 'http-equiv': 'pragma', content: 'no-cache' }, { 'http-equiv': 'cache-control', content: 'no-cache' }, { 'http-equiv': 'expires', content: '0' }, { content: 'telephone=no', name: 'format-detection' } ], // html head 中創(chuàng)建 script 標簽 script: [ { innerHTML: require('./assets/js/flexible_nuxt'), type: 'text/javascript', charset: 'utf-8'} ], // 不對<script>標簽中內容做轉義處理 __dangerouslyDisableSanitizers: ['script'] }, // Global CSS css: ['~/assets/css/reset.css', '~/assets/css/main.less'], // Global env env: { __ENV: process.env.__ENV }, build: { vendor: ['axios'], postcss: [ require('postcss-px2rem')({ remUnit: 75 }) ], extend (config, ctx) { if (ctx.isClient) { // 拓展 webpack 配置 config.entry['polyfill'] = ['babel-polyfill'] config.module.rules.push({ enforce: 'pre', test: /\.(js|vue)$/, loader: 'eslint-loader', exclude: /(node_modules)/ }) // 添加 alias 配置 Object.assign(config.resolve.alias, { 'utils': path.resolve(__dirname, 'utils') }) } } }, plugins: [{src: '~plugins/toast', ssr: false}, {src: '~plugins/dialog', ssr: false}] }
HTML頭部標簽管理:
Nuxt.js 通過 vue-meta 實現頭部標簽管理,在 nuxt.config.js
中的 head
配置。所有的頁面都會走這個配置,如果想要修改某一頁面的title,可以在 pages/**.vue 文件下,添加如下配置,這時該頁面的標題就變成了“收車費”,其余頁面還保持原有標題不變。
在config header配置中, __dangerouslyDisableSanitizers: ['script']
主要是為了不對<script>標簽中內容做轉義處理??聪旅娴睦?#127792;:
head: { title: 'myTitle', meta: [ { charset: 'utf-8' }, { 'http-equiv': 'pragma', content: 'no-cache' }, { 'http-equiv': 'cache-control', content: 'no-cache' }, { 'http-equiv': 'expires', content: '0' }, { content: 'telephone=no', name: 'format-detection' } ], script: [ { innerHTML: 'console.log("hello")', type: 'text/javascript', charset: 'utf-8'} ] },
生成 html:
<script data-n-head="true" type="text/javascript" charset="utf-8">console.log("hello")</script>
我們發(fā)現 vue-meta 把引號做了轉義處理,加入 __dangerouslyDisableSanitizers: ['script']
后,就不會再對這些字符做轉義了,該字段使用需慎重!
3)路由
Nuxt.js 依據 pages 目錄結構,自動生成 vue-router
模塊的路由配置。
假設 pages 的目錄結構如下:
那么,Nuxt.js 自動生成的路由配置如下:
嵌套路由:
創(chuàng)建內嵌子路由,需要添加一個 Vue 文件,同時添加一個與該文件同名的目錄用來存放子視圖組件。在父級 Vue 文件內增加 <nuxt-child/> 用于顯示子視圖內容。
4)布局
Nuxt.js布局方式如下圖所示:
layouts對應目錄中的layouts文件夾,默認pages下的頁面走的都是 layouts/default.vue 布局方式,如下圖。其中<nuxt/>可以類似vue
中slot
插槽的概念,pages/**.vue中的內容會插在<nuxt/>
內。
此外,如果想要某一頁面,不走默認布局方式,可以在vue文件中配置layouts,如下。
<script> export default { layout: 'demo_layout', ... } </script>
5)vuex
在根目錄創(chuàng)建 store 目錄,就會默認引用 vuex 模塊,除此之外,還進行了以下的操作:1)將 vuex 模塊 加到 vendors 構建配置中去;2)設置 Vue 根實例的 store 配置項。
Nuxt.js 支持兩種使用 store 的方式:
- 普通方式:store/index.js 返回一個 Vuex.Store 實例
- 模塊方式:store 目錄下的每個 .js 文件會被轉換成為狀態(tài)樹指定命名的子模塊 (當然,index 是根模塊,相當于設置了namespaced: true)
Nuxt.js提供了模塊方式的簡單寫法:使用狀態(tài)樹模塊化的方式,store/index.js 不需要返回 Vuex.Store 實例,直接將 state、mutations 和 actions 暴露出來即可。示例如下:
export const state = () => ({ accesstoken: '' }) export const mutations = { setAccesstoken (state, accesstoken) { state.accesstoken = accesstoken } }
6)異步數據 asyncData
Nuxt.js 增加了一個 asyncData 方法,用于 在設置組件數據 之前 能夠異步獲取 或 處理數據。
由于 asyncData
是在組件 初始化 之前被調用的,所以不能通過 this
引用組件的實例對象,可以使用上下文對象來實現某些功能,可參考 context api
示例🌰:
asyncData (params) { let accesstoken = params.route.query.accesstoken // request 基于 axios 封裝的函數 return request({ url: '/drivers/banks', method: 'get', headers: { accesstoken } }) .then(res => { let { bankInfo } = res.data return { banksData: bankInfo, accesstoken } }) .catch(err => { return error({ message: 'accesstoken not found', statusCode: 404 }) }) }
上述代碼,會在 組件初始化 之前,請求'/drivers/banks'
接口,接口返回的數據會 融合在 data 中,一并返回模版顯示。在瀏覽器中,使用Vue DevTools可以清晰的查看到 banksData
, accesstoken
都在data中。
在調試中發(fā)現,刷新頁面時,該請求是在服務端發(fā)送的,由其他頁面回退到該頁面時,請求是在客戶端發(fā)送的。
7)fecth方法
與 asyncData
方法類似,不同的是它不會設置組件的數據,作用是設置 store
數據。
五、總結
本項目在開發(fā)中,使用的是 1.0.0-rc9 版本,我們正在積極嘗試遷移到 1.0.0 正式版本。但是,1.0.0-rc9 版本,未見明顯問題,比較穩(wěn)定,足以投入到生產中。
本文主要介紹 Nuxt.js 的特性,后面還會和大家分享踩的坑。文中有任何表述不清或不當的地方,歡迎大家批評指正。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Vue父子組件方法this.$emit()有時候不觸發(fā)問題及解決
這篇文章主要介紹了Vue父子組件方法this.$emit()有時候不觸發(fā)問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05Vue基于vuex、axios攔截器實現loading效果及axios的安裝配置
這篇文章主要介紹了Vue基于vuex、axios攔截器實現loading效果及axios的安裝配置,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-04-04Vue配合Vant使用時area省市區(qū)選擇器的使用方式
這篇文章主要介紹了Vue配合Vant使用時area省市區(qū)選擇器的使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01使用vue-cli+webpack搭建vue開發(fā)環(huán)境的方法
這篇文章主要介紹了使用vue-cli+webpack搭建vue開發(fā)環(huán)境的方法,需要的朋友可以參考下2017-12-12