前言

由于公司业务所需,再加上之前掌握Vue.js相关知识,正好趁着业务的需求,大致学习下Nuxt.js框架。

Nuxt.js是Vue.js通用框架,其实它就是Vue.js的SSR简化版,无非把配置调整更加简单。

具体可以去官网查看下:https://zh.nuxtjs.org/

环境搭建

首先搭建基础环境:

npm install vue-cli -g
npm install create-nuxt-app -g
nuxt -v #输出版本则安装成功

初始化项目:

npx create-nuxt-app <项目名>
#或者
yarn create nuxt-app <项目名>

如果npx提示不存在执行:

npm install -g npx

根据终端提示自行选择配置。

目录详解

|-- .nuxt                            // Nuxt自动生成,临时的用于编辑的文件,build
|-- assets                           // 用于组织未编译的静态资源入LESS、SASS 或 JavaScript
|-- components                       // 用于自己编写的Vue组件,比如滚动组件,日历组件,分页组件
|-- layouts                          // 布局目录,用于组织应用的布局组件,不可更改。
|-- middleware                       // 用于存放中间件
|-- pages                            // 用于存放写的页面,我们主要的工作区域
|-- plugins                          // 用于存放JavaScript插件的地方
|-- static                           // 用于存放静态资源文件,比如图片
|-- store                            // 用于组织应用的Vuex 状态管理。
|-- .editorconfig                    // 开发工具格式配置
|-- .eslintrc.js                     // ESLint的配置文件,用于检查代码格式
|-- .gitignore                       // 配置git不上传的文件
|-- nuxt.config.json                 // 用于组织Nuxt.js应用的个性化配置,已覆盖默认配置
|-- package-lock.json                // npm自动生成,用于帮助package的统一性设置的,yarn也有相同的操作
|-- package.json                     // npm包管理配置文件

路由配置和参数传递

参考文件:路由

其实就是根据文件夹自动生成路由配置,文档说的很清楚。其次注意SPA链接:,一直以为用的是默认vue-router组件...

参数传参实现很简单,修改首页pages/index.vue

<nuxt-link class="button--grey" :to="{name: 'about',params: {aboutID: 123,aboutTitle: 'About'}}">about</nuxt-link>

修改pages/about/index.vue

<template>
  <div class="about">
    <h2>about</h2>
 
    <p>参数:{{$route.params.aboutID}}</p>
    <p>参数:{{$route.params.aboutTitle}}</p>
    <p>
      <nuxt-link :to="{name: 'index'}">首页</nuxt-link>
    </p>
  </div>
</template>

这样实现了简单的参数传递。

动态路由和参数校验

例如从一个数据列表跳转到详细页,新闻列表到新闻详细页这样一个过程:pages/news=>pages/news/:id,其次:id类型为Number类型,不可出现其它字符类型,所以需要做个参数校验。大致这样一个实现过程。具体可以查看文档:动态路由

pages/news/index.vue

<template>
  <div class="news">
    <h2>新闻列表</h2>
    <ul>
      <nuxt-link tag="li" to="/news/1"><a>新闻1</a></nuxt-link>
      <nuxt-link tag="li" to="/news/2"><a>新闻2</a></nuxt-link>
      <nuxt-link tag="li" to="/news/我的"><a>新闻3(路由校验)</a></nuxt-link>
    </ul>
 
    <nuxt-link class="button--grey" :to="{name: 'index'}">首页</nuxt-link>
  </div>
</template>

pages/news/_id.vue

<template>
  <div class="news-detail">
    <h2>新闻详细页</h2>
    <p>
      新闻ID:{{$route.params.id}}
    </p>
    <p>
      <nuxt-link :to="{name: 'news'}">新闻列表</nuxt-link>
    </p>
    <p>
      <nuxt-link :to="{name: 'index'}">首页</nuxt-link>
    </p>
  </div>
</template>
<script>
  export default {
    validate({ params }) {
      //只适配数字的路由
      return /^\d+$/.test(params.id)
    }
  }
</script>

过渡动画

Nuxt.js提供两种方法为路由提供动画效果,一种是全局的,一种是针对单独页面制作:页面过渡动画

文档讲得还算可以,我这里实现的是新闻列表到详细页是右滑动进入,而详细页到列表页是左滑动推出,实现如下:pages/news/index.vue

<template>
  <div class="news">
    <h2>新闻列表</h2>
    <ul>
      <nuxt-link tag="li" to="/news/1"><a>新闻1</a></nuxt-link>
      <nuxt-link tag="li" to="/news/2"><a>新闻2</a></nuxt-link>
      <nuxt-link tag="li" to="/news/我的"><a>新闻3(路由校验)</a></nuxt-link>
    </ul>
 
    <nuxt-link class="button--grey" :to="{name: 'index'}">首页</nuxt-link>
  </div>
</template>
<script>
  export default {
    head() {
      return {
        title: '新闻列表'
      }
    },
 
    transition(to, from) {
      //console.log("列表页", to);
      if (to.name === 'news') {
        //设置动画名称
        return 'slide-left'
      } else {
        return 'slide-right'
      }
    }
  }
</script>
 

pages/_id.vue

<template>
  <div class="news-detail">
    <h2>新闻详细页</h2>
    <p>
      新闻ID:{{$route.params.id}}
    </p>
    <p>
      <nuxt-link :to="{name: 'news'}">新闻列表</nuxt-link>
    </p>
    <p>
      <nuxt-link :to="{name: 'index'}">首页</nuxt-link>
    </p>
  </div>
</template>
<script>
  export default {
    validate({ params }) {
      //只适配数字的路由
      return /^\d+$/.test(params.id)
    },
    head() {
      return {
        title: "新闻详细页"
      }
    },
    transition(to, from) {
      //console.log("详细页", to);
      if (to.name === 'news-id') {
        //设置动画名称
        return 'slide-right'
      } else {
        return 'slide-left'
      }
    }
  }
</script>

然后在全局样式表添加:

/*自定义动画*/
.slide-right-enter-active,
.slide-right-leave-active,
.slide-left-enter-active,
.slide-left-leave-active {
  will-change: transform;
  transition: all .5s;
  position: absolute;
}
 
.slide-right-enter {
  opacity: 0;
  transform: translate3d(-100%, 0, 0);
}
 
.slide-right-leave-active {
  opacity: 0;
  transform: translate3d(100%, 0, 0);
}
 
.slide-left-enter {
  opacity: 0;
  transform: translate3d(100%, 0, 0);
}
 
.slide-left-leave-active {
  opacity: 0;
  transform: translate3d(-100%, 0, 0);
}

获取数据

文档:异步数据

文档写得比较详细,获取数据使用的是axios类库,在安装脚手架可以选择是否安装它,如果你没有安装的请根据这里步骤安装

asyncData这个方法返回的就是设定好data()里的数据。

所以实现获取方法很简单:

<template>
  <div>
    {{ip}}
  </div>
</template>
 
<script>
  export default {
    asyncData(context) {
      return context.$axios.get('http://icanhazip.com').then((res) => {
        return {
          ip: res.data
        }
      })
    }
  }
</script>

但上面的方法比较过时,可以利用异步获取数据编写:

<template>
  <div>
    {{ip}}
  </div>
</template>
 
<script>
  export default {
    async asyncData({ app }) {
      const ip = await app.$axios.$get('http://icanhazip.com')
      return { ip }
    }
  }
</script>

根据文档上面有三种方法,建议使用异步获取数据方法更好。

自定义路由

可以参考这里的实例:自定义路由

我在列表页填写:

<template>
  <div class="blog">
    <h2>Hello My Blog</h2>
    <ul>
      <li v-for="item in blog">
        <nuxt-link :to="'/blog/'+item.post_id">{{ item.title }}</nuxt-link>
      </li>
    </ul>
    <p>
      <nuxt-link :to="{name: 'index'}">首页</nuxt-link>
    </p>
  </div>
</template>
 
<script>
  export default {
    async asyncData({ app }) {
      let api = 'http://spider.dcloud.net.cn/api/news';
      const blog = await app.$axios.$get(api);
      return { blog };
    }
  }
</script>

详细页:

<template>
  <div class="blog-detail">
    <h2>博文详细页</h2>
    <p>
      博文ID:{{$route.params.id}}
    </p>
    <p v-html="blogInfo.content"></p>
    <p>
      <nuxt-link :to="{name: 'blog'}">新闻列表</nuxt-link>
    </p>
    <p>
      <nuxt-link :to="{name: 'index'}">首页</nuxt-link>
    </p>
  </div>
</template>
 
<script>
  export default {
    validate({ params }) {
      //只适配数字的路由
      return /^\d+$/.test(params.id)
    },
    async asyncData(context) {
      let api = 'http://spider.dcloud.net.cn/api/news/36kr/' + context.params.id;
      const blogInfo = await context.$axios.$get(api);
      return { blogInfo };
    }
  }
</script>

大概这样效果就出来了。