VUE SSR服务器端渲染NUXT采坑总结

初始化创建项目

yarn create nuxt-app <项目名>

css预编译

安装 yarn add node-sass scss-loader sass-loader --save-dev

路由管理

在nuxt中路由已经被集成到框架中,所以不需要再单独引入配置,而且当页面文件创建后, router会生成响应的路由,路由文件在.nuxt/router.js文件,用法上基本不变, 与vue-router用法不同部分记录如下

跳转与传参

  • nuxt路由跳转同样是分为两种方式(声明式和编程式),不同的是在nuxt中用跳转标签nuxt-link而不是router-link
  • 传参demo如下
 1  <nuxt-link :to="{name:'home',params:{newsId:3306}}">home1</nuxt-link>
 2     接收参数
 3     asyncData({ params }) {
 4         console.log('home1', params);
 5     },
 6     <nuxt-link :to="{path:'home',query:{newsId:3306}}">home2</nuxt-link>
 7     接收参数
 8     asyncData({ query }) {
 9         console.log('home2', query);
10     },

页面切换动效

路由动效分为全局动效和单独页面动效

  • 创建动效文件,在asset文件下创建动效样式文件(这里定义文件名changePage.css)
  • 定义动画效果,这里定义简单的淡入淡出效果
// 页面默认的页面切换类名为page-enter、page-enter-active、page-leave-active
.page-enter-active,
.page-leave-active {
  transition: opacity 1s;
}

.page-enter,
.page-leave-active {
  opacity: 0;
}

引入定义的动效文件,在nuxt.config.js文件中配置中引入该css文件

 

 

 定义单独页面动效

  • 在页面文件中定义样式类名
1 export default {
2     transition: 'home'
3 }

在css文件中定义动画效果

.home-enter-active,
.home-leave-active {
  transition: all 2s;
  font-size: 12px;

}

.home-enter,
.home-leave-active {
  opacity: 0;
  font-size: 40px;
}

嵌套路由

开发业务中,有时难免会遇到需要二级甚至多层路由嵌套,官方文档中的二级路由介绍也是过于简单,为此又多掉了几根头发 这里就拿官网文档的例子作为讲解

 1 第一:假设要创建一个user的二级路由,文件结构如:
 2 
 3 pages/
 4 --| users/  //2、最容易创建与user.vue文件同名的文件夹,这样nuxt就会识别出我们的意图,原来是要创建嵌套路由
 5             //假如文件夹与user.vue不同名,那么该文件夹下的文件同样被生成一级路由
 6 -----| _id.vue
 7 -----| index.vue
 8 --| users.vue // 1、首先要有user.vue文件
 9 
10 第二:Nuxt.js 自动生成的路由配置如下:
11 router: {
12   routes: [
13     {
14       path: '/users',
15       component: 'pages/users.vue',
16       children: [
17         {
18           path: '',
19           component: 'pages/users/index.vue',
20           name: 'users'
21         },
22         {
23           path: ':id',
24           component: 'pages/users/_id.vue',
25           name: 'users-id'
26         }
27       ]
28     }
29   ]
30 }
31 第三:在一级页面中显示二级页面
32 <template>
33     <div class="page-me">
34         <div>一级页面的相关内容、、、</div>
35         <nuxt-child /> //二级页面的视图窗口,相当于Vue Router的<router-view></router-view>
36     </div>
37 </template>

路由拦截/鉴权

nuxt的路由拦截与Vue Router不同,需要引入中间件 的概念,好在文档介绍比较容易理解,现梳理如下

  • 需要在指定的文件夹middleware/ 下创建路由拦截文件(文件不限数量)
  • 一个中间件接收 context 作为第一个参数,context包含了包括vuex等在内相关数据信息,以此通过数据执行相关逻辑
export default function (context) {
  context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent
}

在nuxt.config.js为全局页面定义路由拦截

module.exports = {
  router: {
    middleware: 'stats'//中间件文件名
  }
}

当然不想全局定义路由拦截也可以为单独的页面定义路由拦截

//具体的页面
export default {
  middleware: 'stats'
}

错误页设置

一个完成项目,404或其他错误页面总是要有的,对此nuxt已经封装了404页面跳转,在layouts文件夹下创建error.vue文件(文件名必须是error.vue),组件接收error对象参数,通过参数的状态码判断页面错误原因

<template>
    <div class="container">
        <h2 v-if="error.statusCode == 404">这是404页面</h2>
        <h2 v-else>这是500页面</h2>
    </div>
</template>
<script>
export default {
    props: ['error'], //nuxt已经封装好返回的
    mounted() {
        console.log('error', this.error);
    }
};
</script>

接口请求

安装

  • 安装:yarn add @nuxtjs/axios
  • 同正常的axios用法相同,不做详细解释

本地代理

  • npm i @nuxtjs/proxy -D
  • 在 nuxt.config.js 配置文件中添加对应的模块,并设置代理
  • 配置了代理,本地开发时axios就不能使用baseURL(打包时,baseURL还是需要放开)
 1 modules: ['@nuxtjs/axios','@nuxtjs/proxy'],
 2 axios: {
 3     proxy: true
 4 },
 5 proxy: {//代理可以设置多个
 6     '/api': {//  /api是指真实接口域名后的一个层级
 7         target: 'http://example.com',//真实接口域名
 8         pathRewrite: {
 9             '^/api' : '/'// "/api"与上面的api相同
10         }
11     }
12 }

axios API封装

  • axios的封装与常规vue项目相同,不同的区别是需要在配置文件中将封装文件引入
plugins: ["@/plugins/element-ui", "~/plugins/api.js"]

 

api访问本地开发

通过设置IP地址,这样就可以通过IP访问本地项目环境

//package.json中配置
"devDependencies": {},
  "config": {
    "nuxt": {
      "host": "0.0.0.0",
      "port": "5000"
    }
  }

asyncData

用于服务端或路由更新之前被调用(如果这里进行接口请求,页面会等接口返回结果后才发生跳转),方法的第一个参数被设定为当前页面的上下文对象(即包含路由、参数等等的一些列信息),可用于请求一个或多个接口,并将返回的数据融合到组件的data中,改方法与mounted函数同级,只在页面模块的文件内生效,在组件模块文件内不生效,由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。

写法一
asyncData(context) {
    return (
        axios.get('https://api.myjson.com/bins/8gdmr1').then(res => {
            return { info: res.data };
            //注意,return返回的最好是key:value对象,直接return导致不利于从实例data中查找使用,如:
            //return (res.data),因为没有设定key,返回的数据虽然融合到实例的data上,但没有key则没法通过key值查找使用
        }),
        axios.get('https://api.myjson.com/bins/8gdmr').then(res => {
            return { info: res.data };
        })
    );
},
写法二
async asyncData({ params }) {
    const { data } = await axios.get('https://api.myjson.com/bins/8gdmr');
    return { info: data };
},

Vuex

nuxt中集成了vuex,不需要新安装插件,Nuxt.js 会尝试找到应用根目录下的 store 目录,并引用 vuex 模块,将 vuex 模块 加到 vendors 构建配置中去,设置 Vue 根实例的 store 配置项。

以上是官方文档原话,大白话翻译就是:nuxt已经集成了vuex不需要手动安装,nuxt会直接找到vuex文件,并把vuex配置到项目中,然后就想正常vue一样使用即可

创建与使用

  • 1、vuex不需要新创建实例,即不需要new Vuex.Store({})
  • 2、state的值应该始终是function,为了避免返回引用类型,会导致多个实例相互影响,即
//正确写法
export const state = () => ({
  counter: 0
})
//错误写法
export const state = {
  counter: 0
}

数据持久化

为避免页面刷新数据状态丢失,需要对vuex数据持久化,nuxt的vuex数据持久化与vue项目稍有不同,这里推荐的是nuxt-vuex-localstorage

  • 安装
  • 配置文件引入
//nuxt.config文件中引入
modules: ["nuxt-vuex-localstorage"]

欢迎大佬指教

项目中虽然在使用vuex,但遇到的问题依然很多,使用起来总是磕磕绊绊,欢迎留言指教

部分配置介绍

meta标签设置

既然是为了SEO优化,那么总是少不了mate标签关键字设定,mate标签分为定义全局和单个页面配置

  • 配置文件定义全局
head: {
    title: process.env.npm_package_name || "",
    meta: [
        { charset: "utf-8" },
        {
            name: "viewport",
            content: "width=device-width, initial-scale=1"
        },
        {
            hid: "description",
            name: "description",
            content: process.env.npm_package_description || ""
        }
    ],
    link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }]
},

设置页面独有关键字

export default {
  data () {
    return {
      title: 'Hello World!'
    }
  },
  head () {
    return {
      title: this.title,
      meta: [
        { hid: 'description', name: 'description', content: 'My custom description' }
      ]
    }
  }
}
posted @ 2020-01-02 14:51  web-慰尘  阅读(954)  评论(0编辑  收藏  举报