> ## Content Index
> Fetch the complete content index at: https://iiong.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Nuxt.js使用笔记
- URL: https://iiong.com/nuxtjs-use-note/
- Published: 2019-05-24T13:57:25.000Z
- Updated: 2026-06-22T15:31:16.000Z
- Description: 目前使用`Nuxt.js`框架做了几个项目，不得不说对比与`Vue-CLI`，`Nuxt.js`实在是懒人必备框架，什么东西都帮你配置好了。所以多少对它有点了解，所以有了这个笔记。希望未来再做类似的地方有个能够参考的笔记。
- Author: 淮城一只猫
- Tags: 编程技术, Vue.js

### Cap1 前言

目前使用`Nuxt.js`框架做了几个项目，不得不说对比与`Vue-CLI`，`Nuxt.js`实在是懒人必备框架，什么东西都帮你配置好了。所以多少对它有点了解，所以有了这个笔记。希望未来再做类似的地方有个能够参考的笔记。

### Cap2 目录结构

```bash
/assets           # 能被webpack处理的项目资源
/components       # 项目组件
/layouts          # 项目布局
/middleware       # 项目中间件
/pages            # 项目页面 页面路由自动生成
/plugins          # 项目插件
/static           # 不被webpack处理的静态资源
/store            # Vuex状态管理目录
nuxt.config.js    # Nuxt.js配置文件
package.json      # npm包管理器文件

```

- `/assets`：这个目录可以存放字体，样式，图片等，这些资源将会被`WebPack`处理器编译最终形态文件。
- `/components`：存放`Vue.js`组件目录，如果`Nuxt.js`特征方法是不能在该目录下使用的。
- `/layouts`：存放项目布局组件，在不同的页面展示双栏或者单栏布局。
- `/middleware`：放置项目中间件应用，例如路由鉴权等功能。
- `/pages`：放置项目视图和路由。Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置。
- `/plugins`：放置声明`Vue`插件或者一些`JavaScript`插件配置文件。
- `/static`：放置静态资源目录，可以启动后直接访问资源。
- `/store`：`Vuex`状态树管理配置文件。
- `nuxt.config.js`：用于`Nuxt.js`配置，覆盖默认设置。

除了上面默认的文件夹，我们可以自己额外添加文件：

- `/api`：存放项目接口文件。
- `/utils`：项目工具类。
- `/test`：单元测试类。

### Cap3 单应用和seo优化

现在绝大项目都是前后端分离的项目，所以纯粹作为静态页面来编写，打开`nuxt.config.js`修改其中的`mode: 'spa'`即可。然后将`package.json`中的`dev`启动方式修改成`"dev": "nuxt --spa"`加快启动编译项目。

> `SPA`：没有服务器端渲染（只有客户端路由导航等）
> 
> `Universal` ：同构应用程序（服务器端呈现+客户端路由导航等）

`Nuxt.js`的SEO优化还算可以，需要注意`header`设置`meta`设置，`Nuxt.js`使用的是[Vue-Meta](https://vue-meta.nuxtjs.org/api/?ref=iiong.com#metainfo-properties)，可以到它文档查看相关设置：

```javascript
export default {
  /*
  ** Headers of the page
  */
  head: {
    htmlAttrs: {
      lang: 'zh-CN',
    },
    title: `淮城一只猫`,
    meta: [
      { charset: 'utf-8' },
      { name: 'apple-mobile-web-app-capable', content: 'yes' }, // iOS浏览器禁止缩放
      { name: 'viewport', content: 'width=device-width, initial-scale=1.0, shrink-to-fit=no, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no' },
      { hid: 'keywords', name: 'keywords', content: 'keywords' },
      { hid: 'description', name: 'description', content: 'description' },
      { name: 'renderer', content: 'webkit' }, // 强制让360浏览器使用Webkit内核
      { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' },
    ],
    script: [],
    link: []
  },
}

```

然后在`pages`每个页面设置：

```javascript
export default {
  head() {
    return {
      title: "淮城一只猫 - 首页"
    };
  }
}

```

如果能力有条件的可以尝试[Nuxt PWA](https://pwa.nuxtjs.org/?ref=iiong.com)，这里就不再详细描述了。

**服务端渲染**

如果在前端展示的时候，给搜索引擎爬虫抓取页面需要注意更好的`SEO`展示，那么就需要服务器端渲染了(SSR)，具体内容可以查看官网文档：[为什么使用服务器端渲染 (SSR)？](https://ssr.vuejs.org/zh/?ref=iiong.com#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93-ssr-%EF%BC%9F)

主要博主做的项目大部分都是后端界面，所以对此也不是太熟，故这里就不再描述了。

### Cap4 样式预处理器

配置样式预处理器也很简单，`Nuxt.js`有自己封装的包：[Nuxt Style Resources](https://github.com/nuxt-community/style-resources-module?ref=iiong.com)，支持`sass`、`less`、`stylus`。现在项目用`sass`处理器比较多，就以它为例：

```bash
yarn add sass-loader node-sass # 安装SASS预处理器
yarn add @nuxtjs/style-resources # 安装nuxt.js 样式模块

```

在`nuxt.config.js`添加：

```javascript
export default {
  modules: [
    '@nuxtjs/style-resources', // 导入模块
  ],
  /*
  ** Sass module
  */
  styleResources: {
   // your settings here
   sass: [
       './assets/style/variables.scss', // 导入样式
   ], // alternative: scss
  }
}

```

到这里就可以愉快的使用样式预处理器编写样式了。

其他处理器安装参考[Nuxt.js styleResources](https://zh.nuxtjs.org/api/configuration-build/?ref=iiong.com#styleresources)。

### Cap5 接口管理

如果项目默认安装`Axios`插件后，对`axios`进行一系列封装也很简单，只需要在`/plugins`新建个`axios.js`文件：

```javascript
import md5 from 'js-md5'
import { getToken, removeToken } from '~/utils/auth'
 
import { Notification } from 'element-ui'
 
export default function ({ $axios, redirect }) {
  // 设置请求头信息
  $axios.setHeader('sign', md5('xxxxxxxxxxxxxxxxxxxxxxxxxxx');
  $axios.setHeader('apiversion', '1.0.0');
  $axios.setHeader('clientfrom', 'pc');
 
  // 当登录的时候 自动设置 请求头 Token
  if (getToken()) {
    $axios.setHeader('token', getToken()); // 设置请求头
  }
 
  /**
   * 请求
   */
  $axios.onRequest(config => {
    // console.log('请求地址：' + config.url)
  });
  /**
   * 响应
   */
  $axios.onResponse(response => {
    // token无效，强制登出
    if( response.data.msg.code === 10001 ) {
      const self = this;
      removeToken();
      Notification({
        title: "系统错误",
        message: "用户Token无效，请重新登陆！",
        type: "error"
      });
      self.$router.push("/login");
    }
  });
  /**
   * 错误
   */
  $axios.onError(error => {
    const code = parseInt(error.response && error.response.status);
    if (code === 400) {
      Notification.error({
        title: '接口错误！',
        message: '接口状态：400，请联系系统管理员！'
      });
      redirect('/400')
    }
    // 接口获取错误
    if (isNaN(code)) {
      Notification.error({
        title: '接口错误！',
        message: '接口状态：未知，请联系系统管理员！'
      });
      redirect('/error')
    }
    // 接口不存在
    if (code === 404) {
      Notification.error({
        title: '接口错误！',
        message: '接口状态：404，请联系系统管理员！'
      });
      redirect('/404')
    }
    // 接口传参错误
    if (code === 500) {
      Notification.error({
        title: '接口错误！',
        message: '接口状态：500，请联系系统管理员！'
      });
      redirect('/500')
    }
  })
}

```

根据自己项目情况增加或者修改。`nuxt.js axios`插件文档可以参考：[Nuxt.js Axios Module](https://axios.nuxtjs.org/?ref=iiong.com)。然后在`nuxt.config.js`导入：

```javascript
export default {
  plugins: [
    '~/plugins/axios', // 导入axios配置文件
  ],
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
  ],
  axios: {
      // ... 根据项目调整参数
  }
}

```

**开启接口反代：**

如果调试后端接口发现跨域的问题，使用接口反代也很简单，根据文档直接在`axios`字段添加：

```javascript
export default {
  /*
  ** Axios module configuration
  */
  axios: {
    // See https://github.com/nuxt-community/axios-module#options
    baseURL: 'http://api.example.com/xx',
    https: false,
    retry: true, // 请求失败重试（仅限3次）
    debug: false,
    proxy: 'http://api.example.com/xx', // 设置代理接口
  },
  // 接口反代
  proxy: {
    '/api/': { target: 'http://api.example.com/xx', pathRewrite: { '^/api/': '' } }
  },
}

```

如果项目是接口是`/index`访问的话，反代接口是`/api/index`就可以访问了。

**可维护接口文件管理**

为了方便后期维护接口管理，可以在项目根目录新建`/api`文件夹，目录下面可以新建一些接口文件：

```bash
/api
- `index.js` # 首页接口管理
- `user.js` # 用户接口管理
- `cart.js` # 购物车接口管理

```

然后我们在`index.js`进行接口编写：

```javascript
import config from '../config'
 
// 根据环境生成接口前缀
const apiPrefix = process.env.NODE_ENV === 'development' ? '/api' : '';
/**
* 获取首页数据
* @param $axios 接口信息
* @returns {Promise<Object>} 返回数据
*/
export const indexApi = ({$axios}) => {
  return new Promise((resolve, reject) => {
    resolve($axios.$get(`${apiPrefix}/v1.index/index`));
  });
};
 
 
/**
* 获取首页数据 V2
* @param $axios 接口信息
* @param liveID 参数ID
* @returns {Promise<Object>} 返回数据
*/
export const indexV2Api = ({$axios}, liveID) => {
  return new Promise((resolve, reject) => {
    resolve($axios.$get(`${apiPrefix}/v2.index/index`, {
      params: {
        id: liveID
      }
    }));
  });
};
 
/**
* 获取首页数据 V3
* @param $axios 接口信息
* @param type 类型
* @param id 参数ID
* @returns {Promise<Object>} 返回数据
*/
export const indexV3Api = ({$axios}, type, id) => {
  return new Promise((resolve, reject) => {
    resolve($axios.$post(`${apiPrefix}/v3.index/index`, {
      type: type,
      id: id
    }));
  });
};

```

然后在项目页面直接导入：

```javascript
import {indexV2Api} from "~/api/index";
 
export default {
  methods: {
     // 异步加载数据
     async initAxiosData() {
         const self = this;
         const {data} = await indexV2Api(self);
         console.log(data); // 返回接口信息
     }
  }
}

```

这边具体信息可以参考文档：[asyncData 方法](https://zh.nuxtjs.org/guide/async-data?ref=iiong.com#asyncdata-%E6%96%B9%E6%B3%95)，但这个方法不能在`components`组件里使用。

### Cap6 中间件的使用

其实中间件这个说法不是太复杂，例如有个功能用的到，就是路由鉴权，就是在用户登录和游客的时候哪些页面能进或者不能进的。直接上demo吧，直接在`/middleware`文件夹新建`permission.js`文件：

```javascript
import {getToken} from '~/utils/auth' // getToken from cookie
/**
* 路由鉴定
* 一些页面游客无权限访问，需要重新登陆
*/
export default async function ({next, route, store}) {
  const whiteList = ['/', '/login', '/future', '/history', '/future/item', '/history/item', '/login/reg', '/login/forget']; // 不重定向白名单
 
  // 用户登录的时候
  if (getToken()) {
    if (route.path === '/login' || route.path === '/login/reg' || route.path === '/login/forget') {
      // 返回首页
      next('/')
    } else {
      // 请求申请个人信息接口 => 当有Token的时候
      store.dispatch("GetUserInfo");
    }
  } else {
    // 未登录访问非白名单的时候
    if (whiteList.indexOf(route.path) === -1) {
      next('/login') // 否则全部重定向到登录页
    }
  }
}

```

如果需要全局配置直接在`nuxt.config.js`配置：

```javascript
module.exports = {
  router: {
    middleware: 'permission'
  }
}

```

这样可以在路由加载之前执行`permission.js`里面的内容。

如果需要只在几个单独的页面执行的话也很简单，只需要打开某个`/page/xxx.vue`可视化文件配置：

```javascript
export default {
  data() {},
  middleware: 'permission',
}

```

参考文档：[Nuxt.js 中间件](https://zh.nuxtjs.org/guide/routing?ref=iiong.com#%E4%B8%AD%E9%97%B4%E4%BB%B6)

### Cap7 使用插件

**Vue组件：**

一般来说使用`Vue.js`插件偏多，例如使用`element-ui`和`Vue-BootStrap`插件，分别新建`element-ui.js`和`bootstrap.js`文件：

```javascript
// Element-ui.js
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/zh-CN'
 
export default () => {
  Vue.use(Element, { locale })
}

```

```javascript
// Bootstrap.js
import Vue from 'vue';
import BootstrapVue from 'bootstrap-vue';
 
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
 
export default () => {
  Vue.use(BootstrapVue)
}

```

然后在`nuxt.config.js`文件引入即可：

```javascript
export default {
  /*
  ** Plugins to load before mounting the App
  */
  plugins: [
    '~/plugins/bootstrap',
    '~/plugins/element-ui',
  ],
  /*
  ** Nuxt.js modules
  */
  modules: [
    // Doc: https://bootstrap-vue.js.org/docs/
    'bootstrap-vue/nuxt',
  ],
  /*
  ** BootStrap-Vue module configuration
  */
  bootstrapVue: {
    bootstrapCSS: false, // or `css`
    bootstrapVueCSS: false // or `bvCSS`
  },
  /*
  ** Build configuration
  */
  build: {
    transpile: [/^element-ui/],
  }
}

```

`vue-bootstrap`安装方法可以参考[Vue Bootstrap nuxtjs-module](https://bootstrap-vue.js.org/docs/?ref=iiong.com#nuxtjs-module)文档，里面讲解比较详细。如果是其他`UI`或者`Vue`插件的话和上面方法差不多，参考各个文档安装方法就行了。

**JavaScript插件：**

如果`Vue.js`组件或者插件无法满足项目需求的话，就需要引入原生`JavaScript`插件文件来满足项目需求，例如我有个项目类型是直播系统，需要引入视频直播`JavaScript`插件（`video.js`视频插件库），可能觉得为什么不需要单独`npm`包导入？主要考虑到这几个文件只在一个页面使用到，作为`npm`导入会被`WebPack`编译成全局使用`js`文件，再加上占用空间很大，所以需要单独抽离出来做个工具包使用。

那么单独最简单的方法就是直接在页面插入`JavaScript`文件就行了，把插入的动作函数封装一个工具库：

```javascript
// -'/utils/loadFile.js'
/**
* 动态插入动态脚本
* @param scripts 动态脚本资源路径，支持url资源路径
* @returns {Promise<array>}
*/
export async function loadScripts(scripts) {
  function get(src) {
    return new Promise(function (resolve, reject) {
      var el = document.createElement("script");
      el.type = "text/javascript";
      el.addEventListener("load", function () {
        resolve(src);
      }, false);
      el.addEventListener("error", function () {
        reject(src);
      }, false);
      el.src = src;
      (document.getElementsByTagName("body")[0] || document.getElementsByTagName("head")[0]).appendChild(el);
    });
  }
 
  const myPromises = scripts.map(async function (script, index) {
    return await get(script);
  });
 
  return await Promise.all(myPromises);
}
 
/**
* 动态插入样式表
* @param scripts 样式脚本资源路径，支持url资源路径
* @returns {Promise<array>}
*/
export async function loadStyles(scripts) {
  function get(src) {
    return new Promise(function (resolve, reject) {
      var el = document.createElement("link");
      el.type = "text/css";
      el.rel = "stylesheet";
      el.addEventListener("load", function () {
        resolve(src);
      }, false);
      el.addEventListener("error", function () {
        reject(src);
      }, false);
      el.href = src;
      document.getElementsByTagName("head")[0].appendChild(el);
    });
  }
 
  const myPromises = scripts.map(async function (script, index) {
    return await get(script);
  });
 
  return await Promise.all(myPromises);
}

```

上面封装的方法是`异步`动态载入资源文件，使用的方法也很简单，直接在视图页面引入这个文件载入函数即可：

```javascript
// -'/pages/item.vue'
import {loadScripts, loadStyles} from "~/utils/loadFile";
export default {
  methods: {
    /**
     * 初始化视频加载资源
     */
    initVideo() {
      const self = this;
      // 检查页面是否存在方法函数
      if (typeof videojs === "undefined") {
        loadScripts(["/video/video.min.js"])
          .then(function () {
            return loadScripts([
              "/video/videojs-http-streaming.min.js",
              "/video/zh-CN.js"
            ]);
          })
          .then(function () {
            return loadStyles([
              "/video/video-js.min.css"
            ]);
          })
          .then(function () {
          // 初始化播放器
          self.livePlayObj = videojs(self.$refs.liveVideoRef, {
            language: "zh-CN"
          }); // 初始化播放器
          // 播放视频
          self.livePlayObj.src({
            src: "http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8",
            type: "application/x-mpegURL",
            withCredentials: true
          });
          self.livePlayObj.load();
          // 开始播放视频
          self.livePlayObj.play();
          });
      }
    },
  }，
  mounted() {
    const self = this;
    self.initLiveData();
  },
}

```

这样可以在页面动态插入脚本，注意的是在插入前检查下脚本函数是否已经加载，要不然重其它页面进入会一直执行插入函数。

### Cap8 页面布局

如果在项目在不同的视图页面使用不同的布局的话，也很简单，在`/layouts`文件夹下声明不同的布局文件就行了。

> default.vue：不可删除也不可修改名字，作为默认布局文件。

例如我新建个`download.vue`布局文件，在视图文件里直接声明布局文件名字即可：

```javascript
export default {
  layout: "download",
}

```

**页面模板**

如果需要大改动页面布局的话，可以在项目根目录下新建`app.html`文件：

```html
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

```

根据项目需求修改内容就行了，然后添加或者修改自己想要东西就行了。

### Cap9 视图页面和路由

`Nuxt.js`视图页面在`/pages`文件夹下面，会根据该目录结构生成`vue-router`路由配置。这边内容直接看[Nuxt.js 路由](https://zh.nuxtjs.org/guide/routing?ref=iiong.com)文档就行了，上面说明写得还算是详细，理解没啥问题。

### Cap10 静态资源

项目静态目录是在`/static`目录下，这个目录对应的是项目地址的`/`，这边没什么要值得主要的，就是在页面引入资源的时候要注意项目在二级目录设定问题：

```html
<template>
  <div class="wscn-http404-container">
    <img class="pic-404__child right" :src="`${homeUrl}images/404_images/404_cloud.png`" alt="404">
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      homeUrl: this.$router.options.base
    }
  },
}
</script>
 
<style rel="stylesheet/scss" lang="scss" scoped>
</style>

```