Nuxt.js實戰

1、爲何選擇Nuxt.js

多數是基於webpack構建的項目,編譯出來的html文件,資源文件都被打包到js中,如下圖404頁面代碼爲例。從代碼中能夠看出,這樣的頁面是不利於 搜索引擎優化(SEO, Search Engine Optimization) ,而且 內容到達時間(time-to-content) (或稱之爲首屏渲染時長)也有很大的優化空間。爲了解決以上問題,引入了 Nuxt.js 框架。javascript

vue官網對於Nuxt.js也是很推薦的,除此以外,Nuxt.js的開發者積極活躍,版本迭代迅速。通過一系列rc版本後,終於在1月9日發佈了 v1.0.0 正式版本css

clipboard.png

圖1. 使用webpack構建的HTML(代碼已格式化)html

clipboard.png

圖2. 使用 Nuxt.js 構建的HTML(代碼已格式化)前端

2、Nuxt.js 簡介

Nuxt.js 是一個基於 Vue.js 的通用應用框架,它預設了利用 Vue.js 開發 服務端渲染(SSR, Server Side Render) 的應用所須要的各類配置,同時也能夠一鍵生成靜態站點。vue

做爲框架,Nuxt.js 爲 客戶端/服務端 這種典型的應用架構模式提供了許多有用的特性,例如異步數據加載、中間件支持、佈局支持等。區別於其餘 vue SSR 框架,Nuxt.js 有如下比較明顯的特性。java

  • 自動代碼分層
  • 強大的路由功能,支持異步數據(路由無需額外配置)
  • HTML頭部標籤管理(依賴 vue-meta 實現)
  • 內置 webpack 配置,無需額外配置

3、項目實戰

一、項目建立

官方提供了基於 vue-cli 腳手架工具,經常使用的有以下三個,更多腳手架工具能夠查看 nuxt-community 。本項目使用的是 express-templatenode

vue init nuxt-community/starter-template <project-name>

vue init nuxt-community/koa-template <project-name>
 
vue init nuxt-community/express-template <project-name>

二、開發

1)目錄結構

├─assets                 資源目錄,未編譯的靜態資源如less、js
├─components             組件目錄
├─layouts                佈局目錄
├─mock                   mock數據
├─node_modules           
├─pages                  頁面目錄
  ├─index.vue
  ├─....                 
├─plugins                插件
├─server                 express服務
├─static                 靜態文件目錄
├─store                  vuex store
├─utils                  工具方法

2)配置

Nuxt.js 默認的配置涵蓋了大部分使用情形,也可經過修改 nuxt.config.js 來覆蓋默認配置。webpack

// 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 中建立 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頭部標籤管理ios

Nuxt.js 經過 vue-meta 實現頭部標籤管理,在 nuxt.config.js 中的 head 配置。全部的頁面都會走這個配置,若是想要修改某一頁面的title,能夠在 pages/**.vue 文件下,添加以下配置,這時該頁面的標題就變成了「收車費」,其他頁面還保持原有標題不變。git

clipboard.png

在config header配置中, __dangerouslyDisableSanitizers: ['script'] 主要是爲了避免對<script>標籤中內容作轉義處理。看下面的例子?:

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(&quot;hello&quot;)</script>

咱們發現 vue-meta 把引號作了轉義處理,加入 __dangerouslyDisableSanitizers: ['script'] 後,就不會再對這些字符作轉義了,該字段使用需慎重!

3)路由

Nuxt.js 依據 pages 目錄結構,自動生成 vue-router 模塊的路由配置。

假設 pages 的目錄結構以下:

clipboard.png

那麼,Nuxt.js 自動生成的路由配置以下:

clipboard.png

嵌套路由

建立內嵌子路由,須要添加一個 Vue 文件,同時添加一個與該文件同名的目錄用來存放子視圖組件。在父級 Vue 文件內增長 <nuxt-child/> 用於顯示子視圖內容。

4)佈局

Nuxt.js佈局方式以下圖所示:

clipboard.png

layouts對應目錄中的layouts文件夾,默認pages下的頁面走的都是 layouts/default.vue 佈局方式,以下圖。其中<nuxt/>能夠相似vueslot插槽的概念,pages/**.vue中的內容會插在<nuxt/>內。

clipboard.png

此外,若是想要某一頁面,不走默認佈局方式,能夠在vue文件中配置layouts,以下。

<script>
export default {
  layout: 'demo_layout',
  ...
}
</script>

5)vuex

在根目錄建立 store 目錄,就會默認引用 vuex 模塊,除此以外,還進行了如下的操做:1)將 vuex 模塊 加到 vendors 構建配置中去;2)設置 Vue 根實例的 store 配置項。

Nuxt.js 支持兩種使用 store 的方式:

  • 普通方式:store/index.js 返回一個 Vuex.Store 實例
  • 模塊方式:store 目錄下的每一個 .js 文件會被轉換成爲狀態樹指定命名的子模塊 (固然,index 是根模塊,至關於設置了namespaced: true)

Nuxt.js提供了模塊方式的簡單寫法:使用狀態樹模塊化的方式,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中。
在調試中發現,刷新頁面時,該請求是在服務端發送的,由其餘頁面回退到該頁面時,請求是在客戶端發送的。

7)fecth方法

asyncData 方法相似,不一樣的是它不會設置組件的數據,做用是設置 store 數據。

5、總結

本項目在開發中,使用的是 1.0.0-rc9 版本,咱們正在積極嘗試遷移到 1.0.0 正式版本。可是,1.0.0-rc9 版本,未見明顯問題,比較穩定,足以投入到生產中。
本文主要介紹 Nuxt.js 的特性,後面還會和你們分享踩的坑。文中有任何表述不清或不當的地方,歡迎你們批評指正。
此外,推薦咱們的公衆號 前端新視野 ,一個很認真的日刊公衆號,歡迎掃描下方二維碼關注!

clipboard.png

相關文章
相關標籤/搜索