Nuxt爬坑

第一節:nuxt.js相關概述

nuxt.js簡單的說是Vue.js的通用框架,最經常使用的就是用來做SSR(服務器端渲染).Vue.js是開發SPA(單頁應用)的,Nuxt.js這個框架,用Vue開發多頁應用,並在服務端完成渲染,能夠直接用命令把咱們製做的vue項目生成爲靜態html。javascript

1.那服務器端渲染到底有什麼好處呢?

主要的緣由時SPA(單頁應用)不利於搜索引擎的SEO操做,Nuxt.js適合做新聞、博客、電影、諮詢這樣的須要搜索引擎提供流量的項目。若是你要做移動端的項目,就不必使用這個框架了。css

2.什麼是SSR?

在認識SSR以前,首先對CSRSSR之間作個對比。html

首先看一下傳統的web開發,傳統的web開發是,客戶端向服務端發送請求,服務端查詢數據庫,拼接HTML字符串(模板),經過一系列的數據處理以後,把整理好的HTML返回給客戶端,瀏覽器至關於打開了一個頁面。這種好比咱們常常據說過的jsp,PHP,aspx也就是傳統的MVC的開發。前端

SPA應用,到了VueReact,單頁面應用優秀的用戶體驗,逐漸成爲了主流,頁面總體式javaScript渲染出來的,稱之爲客戶端渲染CSRSPA渲染過程。由客戶端訪問URL發送請求到服務端,返回HTML結構(可是SPA的返回的HTML結構是很是的小的,只有一個基本的結構,如第一段代碼所示)。客戶端接收到返回結果以後,在客戶端開始渲染HTML,渲染時執行對應javaScript,最後渲染template,渲染完成以後,再次向服務端發送數據請求,注意這裏時數據請求,服務端返回json格式數據。客戶端接收數據,而後完成最終渲染。vue

SPA雖然給服務器減輕了壓力,可是也是有缺點的:java

  1. 首屏渲染時間比較長:必須等待JavaScript加載完畢,而且執行完畢,才能渲染出首屏。
  2. SEO不友好:爬蟲只能拿到一個div元素,認爲頁面是空的,不利於SEO

爲了解決如上兩個問題,出現了SSR解決方案,後端渲染出首屏的DOM結構返回,前端拿到內容帶上首屏,後續的頁面操做,再用單頁面路由和渲染,稱之爲服務端渲染(SSR)。node

SSR渲染流程是這樣的,客戶端發送URL請求到服務端,服務端讀取對應的url的模板信息,在服務端作出html數據的渲染,渲染完成以後返回html結構,客戶端這時拿到的以後首屏頁面的html結構。因此用戶在瀏覽首屏的時候速度會很快,由於客戶端不須要再次發送ajax請求。並非作了SSR咱們的頁面就不屬於SPA應用了,它仍然是一個獨立的spa應用。android

SSR是處於CSRSPA應用之間的一個折中的方案,在渲染首屏的時候在服務端作出了渲染,注意僅僅是首屏,其餘頁面仍是須要在客戶端渲染的,在服務端接收到請求以後而且渲染出首屏頁面,會攜帶着剩餘的路由信息預留給客戶端去渲染其餘路由的頁面。webpack

Nuxt.js是特色(優勢):ios

  • 基於Vue
  • 自動代碼分層
  • 服務端渲染
  • 強大的路由功能,支持異步數據
  • 靜態文件服務
  • EcmaScript6EcmaScript7的語法支持
  • 打包和壓縮JavaScriptCss
  • HTML頭部標籤管理
  • 本地開發支持熱加載
  • 集成ESLint
  • 支持各類樣式預編譯器SASSLESS等等
  • 支持HTTP/2推送

第二節:Nuxt環境搭建

1.nuxt.js安裝

在使用npm前你須要安裝Node到系統中。若沒有安裝參考此連接 www.cnblogs.com/zhouyu2017/…

(1)用npm來安裝vue-cli這個框架。

npm install vue-cli -g
複製代碼

安裝完成後可使用vue -V 來測試是否安裝成功。(注意:這裏要使用大寫的V,小寫無效)。

(2)使用vue安裝 nuxt

安裝好vue-cli後,就可使用init命令來初始化Nuxt.js項目。

vue init nuxt/starter
複製代碼

這時候他會在github上下載模版,而後會詢問你項目的名稱叫什麼,做者什麼的,這些徹底能夠根據本身的愛好填寫。

(3)使用npm install安裝依賴包

npm install
複製代碼

這個過程是要等一會的,若是你這個過程安裝失敗,能夠直接誒刪除項目中的node_modules文件夾後,從新npm install進行安裝。

(4)使用npm run dev 啓動服務

(5)在瀏覽器輸入 localhost:3000,能夠看到結果,以下:

2.第一個Nuxt應用程序安裝

npm i create-nuxt-app -g
create-nuxt-app my-nuxt-demo
cd my-nuxt-demo
npm run dev
複製代碼

安裝嚮導:

Project name                                //  項目名稱
Project description                         //  項目描述
Use a custom server framework               //  選擇服務器框架
Choose features to install                  //  選擇安裝的特性
Use a custom UI framework                   //  選擇UI框架
Use a custom test framework                 //  測試框架
Choose rendering mode                       //  渲染模式
Universal                                   //  渲染全部鏈接頁面
Single Page App                             //  只渲染當前頁面
複製代碼

3.Nuxt 渲染流程

一個完整的服務器請求到渲染的流程

img

經過上面的流程圖能夠看出,當一個客戶端請求進入的時候,服務端有經過nuxtServerInit這個命令執行在Storeaction中,在這裏接收到客戶端請求的時候,能夠將一些客戶端信息存儲到Store中,也就是說能夠把在服務端存儲的一些客戶端的一些登陸信息存儲到Store中。以後使用了中間件機制,中間件其實就是一個函數,會在每一個路由執行以前去執行,在這裏能夠作不少事情,或者說能夠理解爲是路由器的攔截器的做用。而後再validate執行的時候對客戶端攜帶的參數進行校驗,在asyncDatafetch進入正式的渲染週期,asyncData向服務端獲取數據,把請求到的數據合併到Vue中的data中,

第三節 :Nuxt目錄結構

# 目錄結構介紹

└─my-nuxt-demo
  ├─.nuxt               // Nuxt自動生成,臨時的用於編輯的文件,build
  ├─assets              // 用於組織未編譯的靜態資源如LESS、SASS或JavaScript,對於不須要經過 Webpack 處理的靜態資源文件,能夠放置在 static 目錄中
  ├─components          // 用於本身編寫的Vue組件,好比日曆組件、分頁組件
  ├─layouts             // 佈局目錄,用於組織應用的佈局組件,不可更改⭐
  ├─middleware          // 用於存放中間件
  ├─node_modules
  ├─pages               // 用於組織應用的路由及視圖,Nuxt.js根據該目錄結構自動生成對應的路由配置,文件名不可更改⭐
  ├─plugins             // 用於組織那些須要在 根vue.js應用 實例化以前須要運行的 Javascript 插件。
  ├─static              // 用於存放應用的靜態文件,此類文件不會被 Nuxt.js 調用 Webpack 進行構建編譯處理。 服務器啓動的時候,該目錄下的文件會映射至應用的根路徑 / 下。文件夾名不可更改。⭐
  └─store               // 用於組織應用的Vuex 狀態管理。文件夾名不可更改。⭐
  ├─.editorconfig       // 開發工具格式配置
  ├─.eslintrc.js        // ESLint的配置文件,用於檢查代碼格式
  ├─.gitignore          // 配置git忽略文件
  ├─nuxt.config.js      // 用於組織Nuxt.js 應用的個性化配置,以便覆蓋默認配置。文件名不可更改。⭐
  ├─package-lock.json   // npm自動生成,用於幫助package的統一設置的,yarn也有相同的操做
  ├─package.json        // npm 包管理配置文件
  ├─README.md
複製代碼

# 配置文件

const pkg = require('./package')
module.exports = {
  mode: 'universal',    //  當前渲染使用模式
  head: {       //  頁面head配置信息
    title: pkg.name,        //  title
    meta: [         //  meat
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: pkg.description }
    ],
    link: [     //  favicon,若引用css不會進行打包處理
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  loading: { color: '#fff' },   //  頁面進度條
  css: [    //  全局css(會進行webpack打包處理)
    'element-ui/lib/theme-chalk/index.css'  
  ],
  plugins: [        //  插件
    '@/plugins/element-ui'
  ],
  modules: [        //  模塊
    '@nuxtjs/axios',
  ],
  axios: {},
  build: {      //  打包
    transpile: [/^element-ui/],
    extend(config, ctx) {       //  webpack自定義配置
    }
  }
}
複製代碼

# Nuxt運行命令

{
  "scripts": {
    //  開發環境
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
    //  打包
    "build": "nuxt build",
    //  在服務端運行
    "start": "cross-env NODE_ENV=production node server/index.js",
    //  生成靜態頁面
    "generate": "nuxt generate"
  }
}
複製代碼

第四節:Nuxt經常使用配置項

1.配置IP和端口

開發中常常會遇到端口被佔用或者指定IP的狀況。咱們須要在根目錄下的package.json裏對config項進行配置。好比如今咱們想把IP配置成127.0.0.1,端口設置1000。

/package.json

"config":{
    "nuxt":{
      "host":"127.0.0.1",
      "port":"1000"
    }
  },
複製代碼

配置好後,咱們在終端中輸入npm run dev,而後你會看到服務地址改成了127.0.0.1:1000.

2.配置全局CSS

在開發多頁項目時,都會定義一個全局的CSS來初始化咱們的頁面渲染,好比把padding和margin設置成0,網上也有很是出名的開源css文件normailze.css。要定義這些配置,須要在nuxt.config.js裏進行操做。

好比如今咱們要把頁面字體設置爲紅色,就能夠在assets/css/common.css文件,而後把字體設置爲紅色。

/assets/css/common.css

html{
    color:red;
}
複製代碼

/nuxt.config.js

css:['~assets/css/normailze.css'],
複製代碼

設置好後,在終端輸入npm run dev 。而後你會發現字體已經變成了紅色。

3.配置webpack的loader

在nuxt.config.js裏是能夠對webpack的基本配置進行覆蓋的,好比如今咱們要配置一個url-loader來進行小圖片的64位打包。就能夠在nuxt.config.js的build選項裏進行配置,相關可參照此連接www.cnblogs.com/ssh-007/p/7…

build: {
    loaders:[
      {
        test:/\.(png|jpe?g|gif|svg)$/,
        loader:"url-loader",
        query:{
          limit:10000,
          name:'img/[name].[hash].[ext]'
        }
      }
    ],
    /*
    ** Run ESLint on save
    */
    extend (config, { isDev, isClient }) {
      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }
    }
  }
複製代碼

4.全局修改seo的head信息

nuxt.config.js文件中,修改title爲wfaceboss:

head: {
    title: 'wfaceboss',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Nuxt.js project' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
複製代碼

修改後重啓服務,即運行 npm run dev,效果以下

img

第五節:Nuxt的路由配置和參數傳遞

Nuxt.js的路由並不複雜,它給咱們進行了封裝,讓咱們節省了不少配置環節。

1.基本路由

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

假設 pages 的目錄結構以下

└─pages
    ├─index.vue
    └─user
      ├─index.vue
      ├─one.vue
複製代碼

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

router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    },
    {
      name: 'user',
      path: '/user',
      component: 'pages/user/index.vue'
    },
    {
      name: 'user-one',
      path: '/user/one',
      component: 'pages/user/one.vue'
    }
  ]
}
複製代碼

2.頁面跳轉

  1. 不要寫成a標籤,由於是從新獲取一個新的頁面,並非SPA
  2. <nuxt-link to="/users"></nuxt-link>
  3. this.$router.push('/users')

3.動態路由

  • 在 Nuxt.js 裏面定義帶參數的動態路由,須要建立對應的如下劃線做爲前綴的 Vue 文件 或 目錄。
  • 獲取動態參數{{$route.params.id}}

4.跳轉路由傳遞參數而且取值

路由常常須要傳遞參數,咱們能夠簡單的使用params來進行傳遞參數,咱們如今向新聞頁面(news)傳遞個參數,而後在新聞頁面進行簡單的接收。

(1)使用nuxt傳遞參數

<template>
  <div>
    <ul>
      <li><nuxt-link :to="`informa/${item.newsCode}-${item.newsType}`"></li>
    </ul>
  </div>
</template>
複製代碼

注意:name其實指向的是路由(文件夾或文件名),而路由死活區分大小寫的 , 因此to後面區分大小寫!!!建議文件夾都寫成小寫的。

img

(2)使用nuxt接收參數

async asyncData(context) {
    let newsCode = context.route.params.code.split('-')[0]
    let newsType = context.route.params.code.split('-')[1]
},
複製代碼

(3)使用this.$router.push的params傳遞參數

傳遞參數  -- this.$router.push({path: ' 路由 ', query: {key: value}})
參數取值  -- this.$route.query.key

注: 使用這種方式,傳遞參數會拼接在路由後面,出如今地址欄
複製代碼

(4)使用this.$router.push的params傳遞參數

傳遞參數  -- this.$router.push({name: ' 路由的name ', params: {key: value}})
參數取值  -- this.$route.params.key

注: 使用這種方式,參數不會拼接在路由後面,地址欄上看不到參數

注意: 因爲動態路由也是傳遞params的,因此在 this.$router.push() 方法中 path不能和params一塊兒使用,不然params將無效。須要用name來指定頁面。
複製代碼

4.項目需求url優化

this.$route.query.key的方式參數顯示在地址欄上, 可是並非咱們想要的, :id?id=``?

因此建議仍是儘可能使用router-link來實現跳轉來解決地址欄的變化,更方便網站的優化

5.路由參數校驗

Nuxt.js 可讓你在動態路由對應的頁面組件中配置一個validate方法用於校驗動態路由參數的有效性。該函數有一個布爾類型的返回值,若是返回true則表示校驗經過,若是返回false則表示校驗未經過。

export default {
  // nuxt中使用validate方法進行路由參數校驗,這個方法必須返回一個布爾值,爲true表示校驗經過,爲false表示校驗失敗。注意validate不能寫到methods屬性中。
  validate(obj) {
    // console.log(obj);
    // return true
    return /^\d+$/.test(obj.params.id)
  }
}
複製代碼

6.嵌套路由

  1. 添加一個Vue文件,做爲父組件
  2. 添加一個與父組件同名的文件夾來存放子視圖組件
  3. 在父文件中,添加組件,用於展現匹配到的子視圖

第六節:Nuxt的路由動畫效果

路由的動畫效果,也叫做頁面的更換效果。Nuxt.js提供兩種方法爲路由提供動畫效果,一種是全局的,一種是針對單獨頁面製做。

1.全局路由動畫

全局動畫默認使用page來進行設置,例如如今咱們爲每一個頁面都設置一個進入和退出時的漸隱漸現的效果。咱們能夠先在根目錄的assets/css下創建一個normailze.css文件。

(1)添加樣式文件

/assets/css/normailze.css(沒有請自行創建)

.page-enter-active, .page-leave-active {
    transition: opacity 2s;
}

.page-enter, .page-leave-active {
    opacity: 0;
}
複製代碼

(2)文件配置

而後在nuxt.config.js里加入一個全局的css文件就能夠了。

css:['assets/css/main.css'],
複製代碼

這時候在頁面切換的時候就會有2秒鐘的動畫切換效果了,可是你會發現一些頁面是沒有效果的,這是由於你沒有是<nuxt-link>組件來製做跳轉連接。你須要進行更改。

好比咱們上節課做的動態路由新聞頁,你就須要改爲下面的連接。

<li><nuxt-link :to="{name:'news-id',params:{id:123}}">News-1</nuxt-link></li>
複製代碼

改過以後你就會看到動畫效果了。

2.單獨設置頁面動效

想給一個頁面單獨設置特殊的效果時,咱們只要在css裏改變默認的page,而後在頁面組件的配置中加入transition字段便可。例如,咱們想給about頁面加入一個字體放大而後縮小的效果,其餘頁面沒有這個效果。

(1)在全局樣式assets/main.css 中添加如下內容

.test-enter-active, .test-leave-active {
    transition: all 2s;
    font-size:12px;
}
.test-enter, .test-leave-active {
    opacity: 0;
    font-size:40px;
}
複製代碼

(2)而後在about/index.vue組件中設置

export default {
  transition:'test'
}
複製代碼

這時候就有了頁面的切換獨特動效了。

總結:在須要使用的頁面導入便可。

第七節:Nuxt的默認模版和默認佈局

在開發應用時,常常會用到一些公用的元素,好比網頁的標題是同樣的,每一個頁面都是如出一轍的標題。這時候咱們有兩種方法,第一種方法是做一個公用的組件出來,第二種方法是修改默認模版。這兩種方法各有利弊,好比公用組件更加靈活,可是每次都須要本身手動引入;模版比較方便,可是隻能每一個頁面都引入。

1.默認模板

Nuxt爲咱們提供了超簡單的默認模版訂製方法,只要在根目錄下建立一個app.html就能夠實現了。如今咱們但願每一個頁面的最上邊都加入「 學習nuxt.js」 這幾個字,咱們就可使用默認模版來完成。

app.html中:

<!DOCTYPE html>
<html lang="en">
<head>
   {{ HEAD }}
</head>
<body>
    <p>學習nuxt.js</p>
    {{ APP }}
</body>
</html>
複製代碼

這裏的{{ HEAD }}讀取的是nuxt.config.js裏的信息,{{APP}} 就是咱們寫的pages文件夾下的主體頁面了。須要注意的是HEAD和APP都須要大寫,若是小寫會報錯的。

注意:若是你創建了默認模板後,記得要重啓服務器,不然顯示不會成功;可是默認佈局是不用重啓服務器的。

2.默認佈局

默認模板相似的功能還有默認佈局,可是從名字上你就能夠看出來,默認佈局主要針對於頁面的統一佈局使用。它在位置根目錄下的layouts/default.vue。須要注意的是在默認佈局裏不要加入頭部信息,只是關於<template>標籤下的內容統一訂製。

需求:咱們在每一個頁面的最頂部放入「學習nuxt.js」 這幾個字,看一下在默認佈局裏的實現。

<template>
  <div>
    <p>學習nuxt.js</p>
    <nuxt/>
  </div>
</template>
複製代碼

這裏的<nuxt/>就至關於咱們每一個頁面的內容,你也能夠把一些通用樣式放入這個默認佈局裏,但會增長頁面的複雜程度。

總結:要區分默認模版和默認佈局的區別,模版能夠訂製不少頭部信息,包括IE版本的判斷;模版只能定製<template>裏的內容,跟佈局有關係。在工做中修改時要看狀況來編寫代碼。

第八節:Nuxt插件的使用

1.ElementUI使用

  1. 下載npm i element-ui -S

  2. 在plugins文件夾下面,建立ElementUI.js文件

    import Vue from 'vue'
    import ElementUI from 'element-ui'
    Vue.use(ElementUI)
    複製代碼
  3. 在nuxt.config.js中添加配置

    css: [
      'element-ui/lib/theme-chalk/index.css'
    ],
    plugins: [
      {src: '~/plugins/ElementUI', ssr: true }
    ],
    build: {
      vendor: ['element-ui']
    }
    複製代碼

2.axios的使用

  1. 安裝npm install --save axios
  2. 使用
import axios from 'axios'

asyncData(context, callback) {
  axios.get('http://localhost:3301/in_theaters')
    .then(res => {
      console.log(res);
      callback(null, {list: res.data})
    })
}
複製代碼
  1. 爲防止重複打包,在nuxt.config.js中配置
module.exports = {
  build: {
    vendor: ['axios']
  }
}
複製代碼

第九節:Nuxt的錯誤頁面和個性meta設置

當用戶輸入路由錯誤的時候,咱們須要給他一個明確的指引,因此說在應用程序開發中404頁面是必不可少的。Nuxt.js支持直接在默認佈局文件夾裏創建錯誤頁面。

1.創建錯誤頁面

在根目錄下的layouts文件夾下創建一個error.vue文件,它至關於一個顯示應用錯誤的組件。

<template>
  <div>
      <h2 v-if="error.statusCode==404">404頁面不存在</h2>
      <h2 v-else>500服務器錯誤</h2>
      <ul>
          <li><nuxt-link to="/">HOME</nuxt-link></li>
      </ul>
  </div>
</template>

<script> export default { props:['error'], } </script>
複製代碼

代碼用v-if進行判斷錯誤類型,須要注意的是這個錯誤是你須要在<script>裏進行聲明的,若是不聲明程序是找不到error.statusCode的。

這裏我也用了一個<nuxt-link>的簡單寫法直接跟上路徑就能夠了。

2.個性meta設置

頁面的Meta對於SEO的設置很是重要,好比你如今要做個新聞頁面,那爲了搜索引擎對新聞的收錄,須要每一個頁面對新聞都有不一樣的title和meta設置。直接使用head方法來設置當前頁面的頭部信息就能夠了。咱們如今要把New-1這個頁面設置成個性的meta和title。

1.咱們先把pages/news/index.vue頁面的連接進行修改一下,傳入一個title,目的是爲了在新聞具體頁面進行接收title,造成文章的標題。

/pages/news/index.vue

<li><nuxt-link :to="{name:'news-id',params:{id:123,title:'nuxt.com'}}">News-1</nuxt-link></li>
複製代碼

2.第一步完成後,咱們修改/pages/news/_id.vue,讓它根據傳遞值變成獨特的meta和title標籤。

<template>
  <div>
      <h2>News-Content [{{$route.params.id}}]</h2>
      <ul>
        <li><a href="/">Home</a></li>
      </ul>
  </div>
</template>

<script> export default { validate ({ params }) { // Must be a number return /^\d+$/.test(params.id) }, data(){ return{ title:this.$route.params.title, } }, //獨立設置head信息 head(){ return{ title:this.title, meta:[ {hid:'description',name:'news',content:'This is news page'} ] } } } </script>
複製代碼

注意:爲了不子組件中的meta標籤不能正確覆蓋父組件中相同的標籤而產生重複的現象,建議利用 hid 鍵爲meta標籤配一個惟一的標識編號。

第十節:asyncData方法獲取數據

Nuxt.js貼心的爲咱們擴展了Vue.js的方法,增長了anyncData,異步請求數據。

1.造假數據

(1)建立遠程數據

在這裏製做一些假的遠程數據,我選擇的網站是myjson.com,它是一個json的簡單倉庫,學習使用是很是適合的。 咱們打開網站,在對話空中輸入JSON代碼,這個代碼能夠隨意輸入,key和value均採用字符串格式建立。

{
  "name": "Nuxt",
  "age": 18,
  "interest": "I love coding!"
}
複製代碼

輸入後保存,網站會給你一個地址,這就是你這個JSON倉庫的地址了。api.myjson.com/bins/1ctwlm

(2)安裝Axios

Vue.js官方推薦使用的遠程數據獲取方式就Axios,因此咱們安裝官方推薦,來使用Axios。這裏咱們使用npm 來安裝 axios。 直接在終端中輸入下面的命令:

npm install axios --save
複製代碼

2.ansycData的promise方法

咱們在pages下面新建一個文件,叫作ansyData.vue。而後寫入下面的代碼:

<script> import axios from 'axios' export default { data(){ return { name:'hello World', } }, asyncData(){ return axios.get('https://api.myjson.com/bins/1ctwlm') .then((res)=>{ console.log(res) return {info:res.data} }) } } </script>
複製代碼

這時候咱們能夠看到,瀏覽器中已經能輸出結果了。asyncData的方法會把值返回到data中。是組件建立(頁面渲染)以前的動做,因此不能使用this.info,

# return的重要性

必定要return出去獲取到的對象,這樣就能夠在組件中使用,這裏返回的數據會和組件中的data合併。這個函數不光在服務端會執行,在客戶端一樣也會執行。
複製代碼

3.ansycData的promise併發應用

async asyncData(context) {
  let [newDetailRes, hotInformationRes, correlationRes] = await Promise.all([
    axios.post('http://www.huanjingwuyou.com/eia/news/detail', {
      newsCode: newsCode
    }),
    axios.post('http://www.huanjingwuyou.com/eia/news/select', {
      newsType: newsType, // 資訊類型: 3環評資訊 4環評知識
      start: 0, // 從第0條開始
      pageSize: 10,
      newsRecommend: true
    }),
    axios.post('http://www.huanjingwuyou.com/eia/news/select', {
      newsType: newsType, // 資訊類型: 3環評資訊 4環評知識
      start: 0, // 從第0條開始
      pageSize: 3,
      newsRecommend: false
    })
  ])
  return {
    newDetailList: newDetailRes.data.result,
    hotNewList: hotInformationRes.data.result.data,
    newsList: correlationRes.data.result.data,
    newsCode: newsCode,
    newsType: newsType
  }
},
複製代碼

4.ansycData的await方法

固然上面的方法稍顯過期,如今都在用ansyc…await來解決異步,改寫上面的代碼。

<script> import axios from 'axios' export default { data(){ return { name:'hello World', } }, async asyncData(){ let {data}=await axios.get('https://api.myjson.com/bins/8gdmr') return {info: data} } } </script>
複製代碼

5.注意事項+生命週期:

  1. asyncData 方法會在組件(限於頁面組件)每次加載以前被調用
  2. asyncData 能夠在服務端或路由更新以前被調用
  3. 第一個參數被設定爲當前頁面的上下文對象
  4. Nuxt會將 asyncData 返回的數據融合到組件的data方法返回的數據一併返回給組件使用
  5. 對於 asyncData 方式實在組件初始化前被調用的,因此在方法內飾沒辦法經過this來引用組件的實例對象

第十一節:靜態資源和打包

1.靜態資源

(1)直接引入圖片
在網上任意下載一個圖片,放到項目中的static文件夾下面,而後可使用下面的引入方法進行引用
<div><img src="~static/logo.png" /></div>
複製代碼

「~」就至關於定位到了項目根目錄,這時候圖片路徑就不會出現錯誤,就算打包也是正常的。

(2)CSS引入圖片
若是在CSS中引入圖片,方法和html中直接引入是同樣的,也是用「~」符號引入。
複製代碼
<style> .diss{ width: 300px; height: 100px; background-image: url('~static/logo.png') } </style>
複製代碼

這時候在npm run dev 下是徹底正常的。

2.打包

用Nuxt.js製做完成後,你能夠打包成靜態文件並放在服務器上,進行運行。

在終端中輸入:

npm run generate
複製代碼

而後在dist文件夾下輸入live-server就能夠了。

總結:Nuxt.js框架很是簡單,由於大部分的事情他都爲咱們作好了,咱們只要安裝它的規則來編寫代碼。

第十二節:nuxt的跨域解決+攔截器

安裝axios

npm install @nuxtjs/axios --save-dev
複製代碼

安裝完成後更改配置信息:

nuxt.config.js

module.exports = {
    modules: [
        // Doc: https://axios.nuxtjs.org/usage
        '@nuxtjs/axios',
    ],
    axios: {
        proxy:true  //  代理
    },
    axios: {
        proxy: true,
        prefix: '/api', // baseURL
        credentials: true,
    },
    proxy: {
        "/eia/":"http://192.168.0.97:8181/",    //  key(路由前綴):value(代理地址)
        changeOrigin: true, // 是否跨域
        pathRewrite: {
          '^/api': '' //路徑重寫
        }
    }
}
複製代碼

既然說到了axios,就不得不提到的一個東西就是攔截器,非常有用在項目開發過程當中必不可少的。

舉個例子:

安裝

npm install @nuxtjs/axios @nuxtjs/proxy --save
複製代碼
module.expores{
  plugins: [
    {
      src: "~/plugins/axios",
      ssr: false
    },
  ],
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
  ],
}
複製代碼

plugins/axios.js

export default ({ $axios, redirect }) => {
  $axios.onRequest(config => {
    console.log('Making request to ' + config.url)
  })

  $axios.onError(error => {
    const code = parseInt(error.response && error.response.status)
    if (code === 400) {
      redirect('/400')
    }
  })
}

export default function (app) {
  let axios = app.$axios; 
 // 基本配置
  axios.defaults.timeout = 10000
  axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

  // 請求回調
  axios.onRequest(config => {})

  // 返回回調
  axios.onResponse(res => {})

  // 錯誤回調
  axios.onError(error => {})
}

複製代碼

第十三節:爬坑

1.NuxtServerError connect ECONNREFUSED 127.0.0.1:80

緣由: asyncData方法異步請求數據時,覺得/api/${params.id}這個接口的網址是 127.0.0.1:80, 因此將請求發送給了127.0.0.1:80,而個人接口服務器並無跑在80端口上,因此報錯。

解決方法:

  1. 將node服務器端口改爲 127.0.0.1:80
  2. 將接口服務器端口改爲 127.0.0.1:80
  3. 將asyncData方法使用的請求url加上域名+端口,以下所示
export default {
  asyncData ({ params }) {
    return axios.get(`https://127.0.0.1:3000/api/${params.id}`)
    .then((res) => {
      return { title: res.data.title }
    })
  }
}

複製代碼

1. 如何在 head 裏面引入js文件?

背景: 在<head>標籤中,以inline的形式引入flexible.js文件。本項目主要爲移動端項目,引入flexible.js 實現移動端適配問題。

Nuxt.js 經過 vue-meta 實現頭部標籤管理,經過查看文檔發現,能夠按照以下方式配置:

head: {
  script: [{ innerHTML: require('./assets/js/flexible'), type: 'text/javascript', charset: 'utf-8'}],
  __dangerouslyDisableSanitizers: ['script']
}
複製代碼

2.nuxt使用less,sass等預處理器

背景:在組件中的<template><script><style> 上使用各類預處理器,加上處理器後,控制檯報錯。

npm install --save-dev node-sass sass-loader
複製代碼

可是解決過程並非很順利的,在閱讀中文文檔時,忽略版本號,按照上面的提示進行操做,發現不能成功,後來各類debug,最後發現了該解決方案。後知後覺的發現了中文文檔的版本號太低,若是須要查看文檔,必定要看最新版本的英文文檔!

3. 如何使用px2rem

背景:在css中,寫入px,經過px2rem loader,將px轉換成rem

在之前的項目中,是經過 px2rem loader實現的,可是在Nuxt.js項目下,添加 css loader 仍是很費力的,由於涉及到vue-loader

想到了一個其餘方案,可使用 postcss 處理。能夠在 nuxt.config.js 文件中添加配置,也能夠在postcss.conf.js文件中添加。

build: {
  postcss: [
    require('postcss-px2rem')({
      remUnit: 75 // 轉換基本單位
    })
  ]
},
複製代碼

4. 如何拓展 webpack 配置

背景:給 utils 目錄添加別名

剛剛說到,Nuxt.js內置了 webpack 配置,若是想要拓展配置,能夠在 nuxt.config.js 文件中添加。同時也能夠在該文件中,將配置信息打印出來。

extend (config, ctx) {
  console.log('webpack config:', config)
  if (ctx.isClient) {
    // 添加 alias 配置
    Object.assign(config.resolve.alias, {
      'utils': path.resolve(__dirname, 'utils')
    })
  }
}
複製代碼

5. 如何添加 vue plugin

背景:本身封裝了一個 toast vue plugin,因爲 vue 實例化的過程沒有暴露出來,不知道在哪一個時機注入進去。

能夠在 nuxt.config.js 中添加 plugins 配置,這樣插件就會在 Nuxt.js 應用初始化以前被加載導入。

module.exports = {
  plugins: ['~plugins/toast']
}
複製代碼

~plugins/toast.js 文件:

import Vue from 'vue'
import toast from '../utils/toast'
import '../assets/css/toast.css'

Vue.use(toast)
複製代碼

6.如何修改環境變量 NODE_ENV

背景:在項目中,設置 3個 NODE_ENV 的值,來對應不一樣的版本。development,本地開發;release,預發佈版本;production,線上版本。其中,預發佈版本比production版本,多出vconsole。

// package.json
"scripts": {
  "buildDev": "cross-env NODE_ENV=release nuxt build && backpack build",
  "startDev": "cross-env NODE_ENV=release PORT=3000 node build/main.js"
  },
複製代碼

打印 process.env.NODE_ENV 依舊是,production

在 backpack 的源碼中,找到了答案,在 執行 backpack build 命令時,會把 process.env.NODE_ENV 修改成 production,而且是寫死的不可配置的......

無奈下,只能在 process.env 下,添加 __ENV 屬性,表明 NODE_ENV

clipboard.png

這時,在頁面中打印出來的信息 process.env.__ENV undefined,可是能夠打印出 process.env.NODE_ENV

能夠經過配置 nuxt.config.js 中的,env屬性,解決該問題。

env: {
  __ENV: process.env.__ENV
}
複製代碼

7. Window 或 Document 對象未定義?

背景: 在引入第三方插件,或者直接在代碼中寫 window 時,控制檯會給出警告,window 未定義。

發生在這個問題的緣由時,node服務端並無windowdocument 對象。解決方法,經過 process.browser 來區分環境。

if (process.browser) {
  // 引入第三方插件
  require('***')
  // 或者修改window對象下某一屬性
  window.mbk = {}
}
複製代碼

8.按需引入(UI框架等等)

例如使用UI框架:element-ui

我找了不少相關文章,並無詳細說明該如何引入。因此我要拿出來將他說明:

先來看下,若是不按需引入vendor.js的體積大小爲:

nuxt.js打包shi'li

第一步,下載依賴:

# 先下載element-ui

npm install element-ui --save

# 若是使用按需引入,必須安裝babel-plugin-component(官網有須要下載說明,此插件根據官網規則不一樣,安裝插件不一樣)

npm install babel-plugin-component --save-dev
複製代碼

安裝好之後,按照nuxt.js中的規則,你須要在 plugins/ 目錄下建立相應的插件文件

文件根目錄建立(或已經存在)plugins/目錄,建立名爲:element-ui.js的文件,內容以下:

import Vue from 'vue'

import { Button } from 'element-ui'    //引入Button按鈕

export default ()=>{
    Vue.use(Button)
}
複製代碼

第二步,引入插件

nuxt.config.js中,添加配置爲:plugins

css:[
'element-ui/lib/theme-chalk/index.css'
],
plugins:[
'~/plugins/element-ui'
]
複製代碼

默認爲:開啓SSR,採用服務端渲染,也能夠手動配置關閉SSR,配置爲:

css:[
'element-ui/lib/theme-chalk/index.css'
],
plugins:[
    {
        src:'~/plugins/element-ui',
        ssr:false    //關閉ssr
    }
]
複製代碼

第三步,配置babel選項

nuxt.config.js中,配置在build選項中,規則爲官網規則:

build: {
      babel:{        //配置按需引入規則
          "plugins":[
              [
                  "component",
                  {
                      "libraryName":"element-ui",
                      "styleLibraryName":"theme-chalk"
                  }
              ]
          ]
      },
    /*
     ** Run ESLINT on save
     */
    extend (config, ctx) {
      if (ctx.isClient) {
        config.module.rules.push({
           enforce: 'pre',
           test: /\.(js|vue)$/,
           loader: 'eslint-loader',
           exclude: /(node_modules)/
        })
      }
    }
 }
複製代碼

此時,咱們在觀察打包之後文件體積大小,如圖:

nuxt.js打包示例

此時,咱們成功完成了按需引入配置。

9.不想服務端渲染的地方

(1)
<no-ssr>
	插件或者組件
</no-ssr>

(2)
nuxt.config.js裏ssr改成false
plugins: [
    {src: '~/plugins/ElementUI', ssr: false }
],
複製代碼

10.nuxt必須在接口地址前加上訪問域名

解決: 可使用axios的baseURL來代理

import Vue from 'vue'
import axios from 'axios'

// axios.defaults.baseURL = "http://www.huanjingwuyou.com/"

axios.defaults.baseURL = "http://localhost:3000/"

// axios.defaults.baseURL = "http://test.huanjingwuyou.com/"

export default axios
複製代碼

第十四節:Nuxt爬坑更新- 判斷設備進行跳轉手機端

nuxt是沒有index.html頁面的, 我們應該在哪裏寫js代碼來判斷設備呢, 下面請看個人代碼吧

1. 引入middleware中間件

  • nuxt.config.js裏經過router來引入middleware中間件

nuxt.config.js代碼以下

export default {
    router: {
        middleware: ["device"],
    },
}
複製代碼

2. 在根目錄新建utils文件而且新建文件deviceType.js

deviceType.js文件代碼以下

/**
 *
 * @param {*} UA ,就是userAgent
 * @returns  type: 設備類型
 *           env: 訪問環境(微信/微博/qq)
 *           masklayer: 就是給外部拿到判斷是否顯示遮罩層的,一些特殊環境要引導用戶到外部去打開訪問
 */
function isWechat(UA) {
    return /MicroMessenger/i.test(UA) ? true : false;
}

function isWeibo(UA) {
    return /Weibo/i.test(UA) ? true : false;
}

function isQQ(UA) {
    return /QQ/i.test(UA) ? true : false;
}

function isMoible(UA) {
    return /(Android|webOS|iPhone|iPod|tablet|BlackBerry|Mobile)/i.test(UA) ?
        true :
        false;
}

function isIOS(UA) {
    return /iPhone|iPad|iPod/i.test(UA) ? true : false;
}

function isAndroid(UA) {
    return /Android/i.test(UA) ? true : false;
}
export function deviceType(UA) {
    if (isMoible(UA)) {
        if (isIOS(UA)) {
            if (isWechat(UA)) {
                return {
                    type: "ios",
                    env: "wechat",
                    masklayer: true,
                };
            }
            if (isWeibo(UA)) {
                return {
                    type: "ios",
                    env: "weibo",
                    masklayer: true,
                };
            }
            if (isQQ(UA)) {
                return {
                    type: "ios",
                    env: "qq",
                    masklayer: true,
                };
            }
            return {
                type: "ios",
            };
        }
        if (isAndroid(UA)) {
            if (isWechat(UA)) {
                return {
                    type: "android",
                    env: "wechat",
                    masklayer: true,
                };
            }
            if (isWeibo(UA)) {
                return {
                    type: "android",
                    env: "weibo",
                    masklayer: true,
                };
            }
            if (isQQ(UA)) {
                return {
                    type: "android",
                    env: "qq",
                    masklayer: true,
                };
            }
            return {
                type: "android",
            };
        }
        return {
            type: "mobile",
        };
    } else {
        return {
            type: "pc",
        };
    }
}
複製代碼

3. 在middleware裏添加device.js文件

device.js代碼以下

// @ts-nocheck
import { deviceType } from "~/utils/deviceType";
export default function(context) {
    // @ts-ignore
    context.userAgent = process.server ?
        context.req.headers["user-agent"] :
        navigator.userAgent;
    // 給全局上下文添加一個屬性來保存咱們返回的匹配信息
    context.deviceType = deviceType(context.userAgent);
    // 這裏注入到store,是由於我部分頁面須要判斷機型請求不一樣的數據,
    // 大家沒有用到的話能夠移除
    // context.store.commit("SetDeviceType", context.deviceType);
    // 如果判斷UA非移動端的,就在這裏作處理了..
    // context.redirect(status,url) 這個能夠重定向到外部網站
    // 如果內部訪問能夠直接用router對象push
    if (context.deviceType.type === "pc") {
        // context.redirect(302,'www.huanjingwuyou.com')    //301是永久重定向,若是你想隨着設備類型改變一直變,請改成302
    } else {
        context.redirect(302,'m.huanjingwuyou.com')    //301是永久重定向,若是你想隨着設備類型改變一直變,請改成302
    }
}
複製代碼

心得:

0. nuxt渲染頁面分爲兩個階段, 服務端渲染和瀏覽器渲染

1. nuxt能夠用服務端渲染階段asyncData來提早獲取到數據, 數據自動存放到data中, 瀏覽器渲染時直接拿data數據

2. asyncData方法會在組件(限於頁面組件)每次會在刷新加載頁面或者切換路由時被調用,順序比beforeCreate和created以前

3. nuxt服務端渲染時生命週期只有兩個鉤子函數created和beforeCreate兩個鉤子函數,

4. async作併發請求

5. 設置head來提升SEO, 局部須要return {}

6. 每次調用接口的時候須要在接口前面加上訪問域名, 能夠經過axios配置axios.defaults.baseURL

7. nuxt用proxy來代理

8. 跳到詳情頁用nuxt-link來跳轉, 這樣url地址參數更有利於seo, 跳轉時域名都是本身拼接上去的

9. 寫一個錯誤頁面, 路由調用失敗或者代碼出現bug, 會跳到錯誤頁面去

10. 公共的靜態頁面能夠寫在assets裏, 而後nuxt.config.js裏引入

11. 發佈線上時須要將.nuxt, assets, package.json, nuxt.config.js, static放到Nginx裏進行代理

BUG

如何在組件中使用異步數據?

若是組件不是和路由綁定的頁面組件,原則上是不可使用異步數據的。由於 Nuxt.js 僅僅擴展加強了頁面組件的 data 方法,使得其能夠支持異步數據處理。

對於非頁面組件,有兩種方式能夠實現數據的異步獲取:

  1. 在組件的 mounted 方法裏面實現異步獲取數據的邏輯,以後設置組件的數據,限制是:不支持服務端渲染。
  2. 在頁面組件的asyncDatafetch方法中進行API調用,並將數據做爲props傳遞給子組件。服務器渲染工做正常。缺點:asyncData或頁面提取可能不太可讀,由於它正在加載其餘組件的數據。 總之,使用哪一種方法取決於你的應用是否須要支持子組件的服務端渲染。

爲何 Nuxt.js 應用的頁面會出現閃爍?

這是由於在開發模式下,爲了經過 Webpack 實現熱加載,CSS代碼是打包在 JavaScript 代碼中,並動態打到頁面中去,從而元素重繪引發了閃爍。

不用擔憂,在生產模式下,CSS代碼會單獨打包至獨立的文件並置於head標籤內,不會出現頁面閃爍的現象。

如何編輯主機和端口配置?

做爲命令參數直接傳遞

nuxt --hostname myhost --port 3333
複製代碼

"scripts": {
  "dev": "nuxt --hostname myhost --port 3333"
}
複製代碼

nuxt.config.js 中配置:

nuxt.config.js 添加:

export default {
  server: {
    port: 8000, // default: 3000
    host: '0.0.0.0', // default: localhost
  },
  // other configs
}
複製代碼

使用 NUXT_HOST 和 NUXT_PORT env 變量

與 HOST 和 PORT 相似,但更具體,以防您須要添加其餘東西。

"scripts": {
  "dev": "NUXT_HOST=0.0.0.0 NUXT_PORT=3333 nuxt"
}
複製代碼

注意: 爲了更好的跨平臺開發支持,您可使用 cross-env 依賴包。

安裝依賴:

npm install --save-dev cross-env
複製代碼

配置cross-env:

"scripts": {
  "dev": "cross-env NUXT_HOST=0.0.0.0 NUXT_PORT=3333 nuxt"
}
複製代碼

使用HOST和PORT env變量

"scripts": {
  "dev": "HOST=0.0.0.0 PORT=3333 nuxt"
}
複製代碼

package.json 中配置 nuxt :

在您的 package.json 文件中添加:

"config": {
  "nuxt": {
    "host": "0.0.0.0",
    "port": "3333"
  }
},
"scripts": {
  "dev": "nuxt"
}
複製代碼
相關文章
相關標籤/搜索