Nuxt.js使用笔记

前言

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

目录结构

/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

单应用和seo优化

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

SPA
:没有服务器端渲染(只有客户端路由导航等)

Universal
:同构应用程序(服务器端呈现+客户端路由导航等)

Nuxt.js
的SEO优化还算可以,如果作为前端展示的话,需要注意 header
设置 meta
设置, Nuxt.js
使用的是 Vue-Meta
,可以到它文档查看相关设置:

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
每个页面设置:

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

如果能力有条件的可以尝试 Nuxt PWA
,这里就不再详细描述了。

样式预处理器

配置样式预处理器也很简单, Nuxt.js
有自己封装的包: Nuxt Style Resources
,支持 sass
less
stylus
。现在项目用 sass
处理器比较多,就以它为例:

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

nuxt.config.js
添加:

export default {
  modules: [
    '@nuxtjs/style-resources', // 导入模块
  ],

  styleResources: {
   // your settings here
   sass: [
       './assets/style/variables.scss', // 导入样式
   ], // alternative: scss
  }
}

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

其他处理器安装参考 Nuxt.js styleResources

接口管理

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

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
。然后在 nuxt.config.js
导入:

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

开启接口反代:

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

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
文件夹,目录下面可以新建一些接口文件:

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

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

import config from '../config'

// 根据环境生成接口前缀
const apiPrefix = process.env.NODE_ENV === 'development' ? '/api' : '';
/**
 * 获取首页数据
 * @param $axios 接口信息
 * @returns {Promise} 返回数据
 */
export const indexApi = ({$axios}) => {
  return new Promise((resolve, reject) => {
    resolve($axios.$get(`${apiPrefix}/v1.index/index`));
  });
};


/**
 * 获取首页数据 V2
 * @param $axios 接口信息
 * @param liveID 参数ID
 * @returns {Promise} 返回数据
 */
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} 返回数据
 */
export const indexV3Api = ({$axios}, type, id) => {
  return new Promise((resolve, reject) => {
    resolve($axios.$post(`${apiPrefix}/v3.index/index`, {
      type: type,
      id: id
    }));
  });
};

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

import {indexV2Api} from "~/api/index";

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

这边具体信息可以参考文档: asyncData 方法
,但这个方法不能在 components
组件里使用。

中间件的使用

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

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
配置:

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

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

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

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

参考文档: Nuxt.js 中间件