如今大多数开发都是基于Vue
或者React
开发的,可以达到快速开发的效果,也有一些不足的地方,Nuxt
可以在服务端作出渲染,而后让搜索引擎在爬取数据的时候可以读到当前页面。javascript
首先要说明一点,咱们能够认为咱们所编写的Vue
项目是一个服务端的项目,虽然编写的仍是Vue
项目,可是Nuxt
是基于服务器环境的。html
就简单的说一下Nuxt
使用。基础只是仍是以官方文档为主,若是博客中哪里有问题,欢迎留言指正。vue
说了这么多,进入正题。java
路由
与传统的Vue
项目不一样的是,咱们在使用Vue
的时候须要配置Vue-Router
信息,在Nuxt
有很关键的一点就是约定优于配置
。page
目录下的全部*.vue
文件会自动生成路由配置。ios
在项目初始化以后,在pages
下面默认有一个index.vue
文件,因此当咱们使用npm run dev
启动项目,而且使用http://localhost:3000/
访问的时候可以正常访问路由。vue-router
为了证明上面这一点,在pages
下面建立一个信息about.vue
文件,而且http://localhost:3000/about
去访问刚刚写的页面。咱们能够按照正常的Vue
页面去开发就行了。npm
page目录element-ui
├─page │ ├─index.vue └───└─about.vue
about.vueaxios
<template> <div> <h2>This About</h2> </div> </template>
建立完成以后使用http://localhost:3000/about
访问该页面,页面可以正常的渲染出来了。就会看到This About
显示在页面中。api
作到这一步以后就应该实现路由之间的跳转了。Vue
开发过程当中,都是使用router-link
标签完成路由之间的跳转,在Nuxt
也一样可使用router-link
,可是Nuxt
仍然推荐使用nuxt-link
,nuxt-link
与router-link
的功能是等效的。
可能会有一些疑问,既然是等效的,为何要使用nuxt-link
呢?官方文档中是这样说的:未来咱们会为nuxt-link
组件增长更多的功能特性,例如资源预加载,用于提高nuxt.js
应用的响应速度。显然嘛,官方不会平白无故的就作出这么一个东西来,确定实在其中作了不少的优化工做的。
稍微的改动一下刚才的about.vue
在里面添加两个标签,一个使用nuxt-link
,一个使用router-link
看下可否正常完成跳转。
about.vue - 更改后
<template> <div> <h2>This About</h2> <nuxt-link to="/">首页</nuxt-link> <router-link to="/">首页</router-link> </div> </template>
既然从路由开始那么就不得不说到子路由,全局路由守卫这些都些在路由中常常用到的应该怎么处理?该怎么解决这些问题。
前面既然说到了Nuxt
会把pages
文件夹下面的全部*.vue
文件编译成路由,那么子路由须要使用文件夹嵌套才行。
接下来就尝试一下。首先要更改一下pgeas
目录结构。
page目录
├─page │ ├─about │ │ ├─detail.vue │ │ └─index.vue └───└─index.vue
注意上面的about
目录,是index.vue
而并不是about.vue
,这里的index.vue
指的是about
路由下的首页,也就是最开始放在与index.vue
同级的那个about.vue
是同样的效果。
about/index.vue
<template> <div> <h2>This About</h2> <nuxt-link to="/">首页</nuxt-link> <router-link to="/">首页</router-link> </div> </template>
about/detail.vue
<template> <div> <h2>This Detail</h2> </div> </template>
如今若是咱们想要访问刚才的那两个路由地址分别就是http://localhost:3000/about
和http://localhost:3000/about/detail
就能看到刚才编写的page
页面了。
若是想要看路由生成究竟是什么样子的?能够在根目录下有一个.nuxt
文件夹,在里面能够看到一个router.js
,这个文件夹下面就是Nuex
生成好的路由信息。
打开文件后翻到最后会有一段这样的代码,是否是很眼熟?这是不就是在编写Vue
项目的时候配置的哪些路由文件么?
router.js
export function createRouter() { return new Router({ mode: 'history', base: decodeURI('/'), linkActiveClass: 'nuxt-link-active', linkExactActiveClass: 'nuxt-link-exact-active', scrollBehavior, routes: [{ path: "/about", component: _9ceb4424, name: "about" }, { path: "/about/detail", component: _18146f65, name: "about-detail" }, { path: "/", component: _d3bf5a4e, name: "index" }], fallback: false }) }
有了这个文件的话咱们就能够清楚的知道,路由的结构了。不只仅这样,还可使用name
去实现路由的跳转了。
须要注意的是,若是你的路由是有文件夹嵌套的话,Nuxt
是用使用-
来拼接路由的name
名称的(如:about-detail
),可是文件夹内部的index.vue
会直接已文件夹的名字做为name
。一旦知道了路由的name
,这样咱们就可使用命令的方式跳转路由了。
再次更改一下about/index.vue
。
about/index.vue
<template> <div> <h2>This About</h2> <nuxt-link :to="{name:'about-detail'}">详情</nuxt-link> <router-link :to="{name:'index'}">首页</router-link> <button @click="onClick">跳转到详情</button> </div> </template> <script> export default { methods: { onClick() { this.$router.push({name:"about-detail"}) } } } </script>
使用路由访问http://localhost:3000/about
地址,分别点击详情、首页与button
,都是可以正常跳转的,与以前的Vue
开发是彻底没有任何区别的。在vue-router
中有一个很重要的一个点就是动态路由
的概念,若是想要实现动态路由应该怎么处理呢?
若是想要在Nuxt
中使用动态路由的话,须要在对应的路由下面添加一个_参数名.vue
的文件,在about
文件下面添加一个_id.vue
page目录
├─page │ ├─about │ │ ├─detail.vue │ │ ├─_id.vue │ │ └─index.vue └───└─index.vue
新建完成以后在去router.js
中看一下更改后的路由结构
export function createRouter() { return new Router({ mode: 'history', base: decodeURI('/'), linkActiveClass: 'nuxt-link-active', linkExactActiveClass: 'nuxt-link-exact-active', scrollBehavior, routes: [{ path: "/about", component: _9ceb4424, name: "about" }, { path: "/about/detail", component: _18146f65, name: "about-detail" }, { path: "/about/:id", component: _6b59f854, name: "about-id" }, { path: "/", component: _d3bf5a4e, name: "index" }], fallback: false }) }
能够明显的看到在/about/:id
这个路由,明显的变化不止这些变更的还有name: "about-id"
再也不是以前的name:about
了。若是想要使用这个id
的话必须在_id.vue
中才能获取到。
**_id.vue**
<template> <div> {{$route.params.name}} {{$route.params.id}} </div> </template>
在_id.vue
中编写以上代码并使用http://localhost:3000/about/ABC
,能够看到在页面中已经展现了当前的id
值。
在实际开发过程中可能params
可能会有多个参数,又应该怎么处理呢?
调整目录结构
// id为可选参数 ├─page │ ├─about │ │ ├─_name | | | └─_id | | | └─index.vue │ │ └─index.vue └───└─index.vue
**about - _name - _id.vue**
<template> <div> {{$route.params.name}} {{$route.params.id}} </div> </template>
弄完以后看下router.js
的变化
export function createRouter() { return new Router({ mode: 'history', base: decodeURI('/'), linkActiveClass: 'nuxt-link-active', linkExactActiveClass: 'nuxt-link-exact-active', scrollBehavior, routes: [{ path: "/about", component: _9ceb4424, name: "about" }, { path: "/about/detail", component: _18146f65, name: "about-detail" }, { path: "/about/:name", component: _2ec9f53c, name: "about-name" }, { path: "/about/:name/:id", component: _318c16a4, name: "about-name-id" }, { path: "/", component: _d3bf5a4e, name: "index" }], fallback: false }) }
这里展现的是第二种状况,id
为必选参数的状况,路由被编译的结果。
虽然路由已经添加了参数,可是id
属性不是必填属性,这样的话不能知足项目需求又要如何处理呢?很简单的,在_id.vue
文件同目录下添加一个index.vue
文件就能够了。
// id为必选参数 ├─page │ ├─about │ │ ├─_name | | | ├─_id.vue | | | └─index.vue │ │ └─index.vue └───└─index.vue
须要注意的是,必定要在_id.vue
文件中使用传入的参数,直接获取在index.vue
中是拿不到任何信息的。可是若是访问http://localhost:3000/about/ABC
这样的路由的话,实在index.vue
中是能够获取到name
参数的。
在刚才的router.js
文件中生成的全部的路由都是平级的,如何实现路由的嵌套,若是想要实现嵌套路由的话,必须有和当前路由同名的文件夹存在,才能完成路由的嵌套。
page目录
├─page │ ├─about | | ├─_id.vue | | └─detaile.vue │ ├─about.vue └───└─index.vue
router.js
export function createRouter() { return new Router({ mode: 'history', base: decodeURI('/'), linkActiveClass: 'nuxt-link-active', linkExactActiveClass: 'nuxt-link-exact-active', scrollBehavior, routes: [{ path: "/about", component: _76687814, children: [{ path: "", component: _9ceb4424, name: "about" }, { path: ":id", component: _6b59f854, name: "about-id" }] }, { path: "/", component: _d3bf5a4e, name: "index" }], fallback: false }) }
更改完目录结构,那咱们嵌套的路由应该如何展现?在vue.js
中开发的时候使用router-view
这个标签完成的。为了性能的优化Nuxt
也提供了一个对应的标签nuxt-child
。
若是想实现嵌套路由传参须要稍微的改动一下目录结构,按照上面的方法实现就行了,下面是一个路由结构的例子。
page目录
├─page │ ├─about │ │ ├─detail | | | ├─_id.vue | | | └─index.vue │ │ └─index.vue └───└─index.vue
router.js
export function createRouter() { return new Router({ mode: 'history', base: decodeURI('/'), linkActiveClass: 'nuxt-link-active', linkExactActiveClass: 'nuxt-link-exact-active', scrollBehavior, routes: [{ path: "/about", component: _76687814, name: "about", children: [{ path: "detail", component: _0a09b97d, name: "about-detail" }, { path: "detail/:id?", component: _fa7c11b6, name: "about-detail-id" }] }, { path: "/", component: _d3bf5a4e, name: "index" }], fallback: false }) }
在_id.vue
中则可使用id这个参数了。访问路由http://localhost:3000/about/detail/123
,依然能够拿到传入的id
为123
的这个参数。
说了这么多了,还有不少问题没得说完,关于路由的全局守卫又应该如何去使用?在Nuxt
根目录下有个plugins
文件夹。首先要作的是在里面建立一个名为router.js
文件。
plugins-router.js
export default ({app}) => { app.router.beforeEach((to,form,next) => { console.log(to) next(); }); }
导出了一个函数,在这个函数中能够经过结构拿到vue
的实例对象名叫app
。须要注意的是,这个beforeEach
函数的执行,有可能会在服务端也会有可能在客户端输出。客户端首次访问的页面会在服务端作输出,一旦渲染完成以后,则不会再在服务端输出,则会一直在客户端进行输出了。
说到这里作个小插曲,那么又该怎么区分当前是在客户端环境仍是服务端环境呢?可使用process.server
获取到当前的运行环境,其获得的是Boolean
值,true
服务端,fasle
客户端。
作了这些以后去访问路由,仿佛没有任何输出,不管实在客户端仍是在服务端,都没有任何打印输出,中间缺乏了步骤,须要在根目录下找到nuxt.config.js
对插件进行配置。
nuxt.config.js
const pkg = require('./package') module.exports = { plugins: [ '@/plugins/element-ui', '@/plugins/router' ] }
因为更改了Nuxt
配置须要重启一下服务,才能正常执行刚刚写入的插件。而后访问刚刚写入的路由,会看在服务端初次渲染的时候,会输出咱们想要的那些东西,进行路由跳转的话,会在客户端输出,这也就证实了Nuxt
只会作首屏的服务器渲染。
路由说了这么接下来须要说一下Nuxt
是如何为指定的路由配置数据作渲染的。其实Nuxt
在作渲染的时候包裹了不少层。首先有一个Document
做为其模板,而后再去寻找其布局的页面,找到对应的页面以后,再根据引用去找到相关的组件进行渲染,数据请求与数据挂载,一系列完成以后,把剩余的路由信息返还给客户端,渲染完成,这个就是Nuxt
简单的渲染流程。
在上面提到了一个布局页面
,这个东西应该去哪里找?又应该怎么作呢?它对于项目而言对于开发又有什么好处?在Nuxt
根目录下有一个layouts
文件夹,下面有一个default.vue
这个文件就是上面提到的渲染页面,也就同等于vue
开发中的App.vue
,在这里能够作不少事情。例如添加一个全局的导航。
在layouts
文件夹添加一个about.vue
文件写入以下内容,接下来须要在pages
下面的about.vue
中通知,对应pages
使用哪一个布局页面,不写则使用默认,而后访问http://localhost:3000/about
相关的页面,只要是和about
相关的页面,都会展现这个内容。
layouts - about.vue
<template> <div> <h2>Aaron 我的博客主页</h2> <nuxt></nuxt> </div> </template>
pages - about.vue
<template> <div> <h2>About</h2> <nuxt-child></nuxt-child> </div> </template> <script> export default { layout:"about" } </script>
访问一下全部与about
页面有关的页面,都会看到Aaron我的博客主页
这个字样,若访问根路由则没法看到的。
若是作过mvc
开发的话,若是页面发生错误会跳转到一个错误页面的。Nuxt
也是有默认的错误页面的,可是全是英文并且样式也不太好看,不能自定义样式。如何自定义错误页面呢?
在layouts
文件夹中新建一个error.vue
文件。
layouts - error.vue
<template> <div> <h1>这里是错误页面</h1> <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>
在error.vue
中能够经过props
拿到一个error
对象,获取到error
错误信息以后能作任何想要作的事情。须要注意的一点是,自定意的错误页面,只能在客户端访问失效的时候才会响应到该页面,若在服务端的话,是没法直接渲染这个页面的。
更改页面配置Nuxt
中有些全局的配置,配置信息在nuxt.config.js
更改其全局配置,pages
文件夹中的*.vue
文件也是能够配置的,页面私有的配置会覆盖掉全局的配置。
举例:
export default { layout:"about", head: { title:"About" } }
在这些全局配置中最重要的一个就是asyncData
这个属性。asyncData
究竟是用来作什么的呢?这个数据能够在设置组件的数据以前能一步获取或者处理数据。也就是说在组件渲染以前先获取到数据,而后等待挂载渲染。
举个例子:
<template> <div> <h2>姓名:{{userInfo.name}}</h2> <h2>年龄:{{userInfo.age}}</h2> <nuxt-child></nuxt-child> </div> </template> <script> let getUserInfo = () => { return new Promise(resolve => { setTimeout(() => { let data = {"name":"Aaron","age":18}; resolve(data); }) }) } export default { layout:"about", head: { title:"About" }, async asyncData(){ const userInfo = await getUserInfo(); return {userInfo} } } </script>
必定要return
出去获取到的对象,这样就能够在组件中使用,这里返回的数据会和组件中的data
合并。这个函数不光在服务端会执行,在客户端一样也会执行。
注意事项:
this
来引用组件的实例对象刚刚提到了一点就是上下问对象,在上线文对象中能够获取到不少东西,如路由参数,错误信息等等等,这里就不做太多赘述了,有了这些能够作一些页面的重定向或者其余工做,好比参数校验,安全验证等工做。
路由扯了一大堆,接下来讲一下如何在Nuxt
中融入axios
的使用。
安装axios
npm install @nuxtjs/axios --save-dev
安装完成后更改配置信息:
nuxt.config.js
module.exports = { modules: [ // Doc: https://axios.nuxtjs.org/usage '@nuxtjs/axios', ], axios: { proxy:true // 代理 }, proxy: { "/api/":"http://localhost:3001/" // key(路由前缀):value(代理地址) } }
主要说名一下proxy
这里,/api/
在请求的时候遇到此前缀则会只指向的代理地址去请求数据。
既然说到了axios
,就不得不提到的一个东西就是拦截器,非常有用在项目开发过程当中必不可少的。
举个例子:
module.expores{ plugins: [ '@/plugins/axios' ], 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') } }) }
总结
说了这么多也许会有些纰漏,或者遗漏的知识点,如有什么错误的地方能够在下方留言,尽快作出改正。谢谢你们花费这么长时间阅读这篇文章。