# 前言
对于单页面的 SEO
大家可能都知道是服务器渲染,比如 Vue
是利用 SSR
来实现的,需要自己配置移动端与服务端等一顿操作,很是不简单。那么有没有一个框架既可以实现 SEO
同时配置还那么麻烦?答案是可定的,那就是我们今天将要分享的 Nust.js
,有兴趣的同学可以看下 官网。
# 安装
npm install -g create-nuxt-app
# 创建项目
create-nuxt-app nuxt-test (这里是你的项目民称)
然后就是一顿选择操作,如下图。
注意:红框处一定选择
SSR
切记 切记 切记,其他选项可根据项目需要进行选择
# 启动项目
按上述操作完成并下载完依赖后,就可以启动项目了
npm run dev
看到以下这两个页面,说明你项目启动成功了
# 路由
Nuxt
会自动检测 pages
文件夹下的所有 .vue
文件,并自动生成路由不需要配置,类似于 uni-app
的路由一样,因此如非必要,pages
文件夹的名称不要随意改动。
路由跳转
语法:
<nuxt-link :to="{name: '你的页面名称'}"> 页面名称 </nuxt-link>
举个栗子:
<nuxt-link :to="{name: 'details'}"> 查看详情页 </nuxt-link>
参数传递:
<nuxt-link :to="{name: '页面名称', params:{参数键: 参数值}}"> 页面名称 </nuxt-link>
<nuxt-link :to="{name: '页面名称', query:{参数键: 参数值}}"> 页面名称 </nuxt-link>
举个栗子:
<nuxt-link :to="{name: 'details', params:{id: '123456'}}"> 查看详情页 </nuxt-link>
<nuxt-link :to="{name: 'details', query:{id: '123456'}}"> 查看详情页 </nuxt-link>
获得参数值:
同 Vue =》this.$route.params.参数名
同 Vue =》this.$route.query.参数名
一级路由
pages
文件夹下的一级.vue
文件或者是一级文件夹下的index.vue
文件都是一级路由,如下图:
about
文件下的index.vue
文件是一级路由about
,只不过是放在了about
文件夹下。当防访问about路由时,会查找有没有一节路由about
, 如果没有就查找about
文件夹并且默认会查找index.vue
文件。不管是那种方式,访问路径都为:http://localhost:3000/about
。
而下边这个index.vue
(news.vue
上头紧挨着的)也是一级路由,只是直接放在了pages
文件夹下的一级目录下,是通常的写法,访问路径为:http://localhost:3000/index
或 http://localhost:3000/news
,分别对应着首页(index.vue
)和 新闻页(news.vue
)。
二级路由
所谓二级路由就是建立 一个一级路由同名的文件夹,这个文件夹下的.vue
文件就是二级路由。例如news.vue
需要建立有一个news
文件夹来存放news
的二级路由, 如下图:
访问路劲分别为:http://localhost:3000/about/aboutChild
与 http://localhost:3000/news/newsChild
一级路由里写一个可以存放二级路由的标签:<nuxt-child />
,访问后的结果如下截图:
注意:我的
about
文件夹是包含了index.vue
文件,在这个文件夹里再建立子组件/二级路由没实现。只能是一级路由news.vue
同级创建一个同名文件夹news
,并这这个文件里创建二级路由页面没有问题。不知道是不是我配置的不对,望大家多多留言。
还有就是,父组件(一级路由)里必须放一个可存放二级路由的地方,类似于solt
,在这里名称叫<nuxt-child />
,否则二级路由不展示。
动态路由
语法:
<a href="/details/1234"> 查看详情页 </a>
注意:如传递的是
id
则需要建立一个_id.vue
的文件作为接收参数的页面,以此类推(页面目录结构如下图,必须这么建,这是一个 nuxt 的约定)。
如上图:about
文件夹里的 index.vue
就是 about
页面,跳转至此页面可以这么写:
<nuxt-link :to="{name: 'about'"> about </nuxt-link>
如果传递参数,则可以这么写(前提是已经创建好了以参数名为名称的页面,如 _id.vue
):
<nuxt-link :to="{name: 'about/123456'"> about </nuxt-link>
这么写就会跳转至 _id.vue
页面而不是 about.vue
页面
在 `_id.vue` 页面接收参数
法一:同 Vue =》 this.$route.params.id
法二:使用 validate 方法,切记、切记、切记 不能使用 this
validate({params, query, store}){
return true; // 直接呈现页面
return false; // 将停止Nuxt.js呈现页面并显示错误页面
return (校验规则:正则、store、promise ...)结果为 true 则呈现页面,否则显示错误页面
}
路由重定向
现在模拟这么一个场景,用户输入http://localhost:3000
默认重定向到news.vue
页面。
方法一:再nuxt.config.js
配置文件里配置
在配置文件`nuxt.config.js`里配置一下内容
router: {
extendRoutes(routes) {
routes.push({
path: "/",
redirect: "/news"
});
}
}
方法二:利用中间件
- 在
middleware
文件夹下创建一个处理重定向的文件redirect.js
(名称随意)。 -
redirect.js
文件书写处理重定向的逻辑:
export default function({ isHMR, app, store, route, parapms, error, redirect }) {
// 如果是热更新则不做处理
if (isHMR) return
if (route.fullPath == '/') {
return redirect('/news');
}
}
- 在配置文件
nuxt.config.js
里引入中间件文件
router: {
middleware: 'redirect'
}
以上就是两种实现重定向的方法,记得重启
,因为更改了配置文件。
法一我这没起作用,欢迎大家评论帮忙解决
# 错误页面跳转(404页面)
Nuxt
框架内置了一个错误页面,很生硬也不友好,如下图:
我们也可以自定义错误页面,只需要在 layouts
文件下创建一个 error.vue
页面作为我们的错误页面,切记名称不能更改哦,只能是 error.vue
, 如下图:
具体容可根据需要自行设置
自定义错误页面,默认接受一个 error
属性
<template>
<div style="text-align: center; font-size: 20px;padding-top: 50px;">
我是自定义错误页面
<br>
{{error}}
</div>
</template>
<script>
export default {
props:['error']
}
</script>
并且 error
是个对象,属性如下图:
当我们使用 axios
在 asyncData
方法里发送请求时,也可以把捕捉的错误信息展现在错误页面:
可见,我需要在 asyncData
方法里接受一个上下文 ctx
,当捕捉到错误时,调用 ctx.error
方法向 error.vue 错误页面
传递错误信息。
# 路由跳转动画效果
全局设置,作用于 pages 下的所有页面
- 第一步:在
assets
文件夹下 创建一个index.css
文件 - 第二步:在
index.css
文件下书写以下内容:
.page-enter-active,.page-leave-active {
transition: opacity .5s;
}
.page-enter,.page-leave-active {
opacity: 0;
}
- 第三步: 在
nuxt.config.js
配置我们写的样式
css: [
'~assets/main.css',
'~assets/index.css'
]
- 这时使用
nuxt-link
跳转就可以实现路由动画了,切记只能是nuxt-link
跳转,否则无效。
针对特定页面,单独设置
- 第二步:在
index.css
文件下书写以下内容:
.about-enter-active,.about-leave-active {
transition: opacity 1s;
font-size: 14px;
background: #fff;
}
.about-enter,.about-leave-active {
opacity: 0;
font-size: 56px;
background: red;
}
- 第二步:在
about
页面增加一个transition
属性,属性值必须是about
。
注意,这里的
transition
的值不一定和页面名称一样,但必须和样式
里的名称保持一致
。
# 默认模板与默认布局
默认模板
- 在项目根目录创建一个
app.html
文件 - 在
app.html
文件里书写一下内容(不局限以下内容):
<!DOCTYPE html>
<html>
<head>
<!-- 读取的是 nuxt.config.js 文件里的 head 配置 -->
{{HEAD}}
</head>
<body>
<h1> 我是测试的默认模板 </h1>
<!-- 每个页面的实体 -->
{{APP}}
</body>
</html>
提示:
{{APP}}
是必填内容,除此之外可跟需要自行填写
- 重启运行之后,每个页面都可看到模板里设置的内容
默认布局
指的就是 layouts
文件夹下的 default.vue
文件,内容如下:
<template>
<div>
<Nuxt />
</div>
</template>
注意:出
<Nuxt />
不能删除外(因为他相当于路由容器),其他内容可根据需求进行书写,所有页面也都能看到。
当然,我们也可以根据不同需要,特定页面可以制定不同的默认布局(也叫视图)。在不指定的情况下,默认所有页面都是使用的layouts
文件夹下的 default.vue
文件。若需指定只需如下步骤
- 在
layouts
文件夹下创建我们的视图暂且叫testLayouts.vue
文件 -
testLayouts.vue
文件内容如下(具体内容肯根据需要自行填写):
<template>
<div>
<Nuxt />
</div>
</template>
<style>
</style>
- 在需要指定这个视图的页面中增加下面这句话:
export default {
layout: 'testLayout'
}
这时再运行指定新默认视图的页面可以看到,已经不是使用的全局默认的视图了,而是我们指定的新视图。
# 数据请求 asyncData
在 vue
里数据请求一般是在 mounted
里去请求,即在也页面挂载完成后去请求的。这样的话还是不能进行 SEO
。我需要在页面加载之前去请求数据,由后端组装好数据返回到前端,这样才符合SEO
。
asyncData
就解决了这个问题,他和 mounted、methods
等属性方法平,如下:
export default {
data(){
return{
}
},
asyncData({isDev, router, store, env, params, req, res, redirect, error}){
},
mounted(){
}
}
这里注意下
asyncData
有这么几个特点:
- 在服务端调用
asyncData
时,可以访问用户请求的req
和res
对象- 在当前页面刷新,服务器执行次函数
- 从其他页面跳转过来,客户端执行次函数
请求数据的话就正常使用axios
就可以,但需要两次return
,例如:
export default {
asyncData(){
return axios({
url:'http://xxx.xxx.xxx'
}).then(res=>{
return { dataList: res.data.data }
})
}
}
第一个
return
是返回一个promise
告诉服务端已经请求完成,在服务端也有类似的这么一句话:this.asyncData().then()
(猜测一下)
第二个return
是让服务端链式调用时保证.then
有结果。
在渲染页面时我就可以用 dataList
作为数据源来渲染,例如:
<div v-for="(item, index) in dataList" :key="index">
<p> {{ item}} </p>
</div>
注意:
return { dataList: res.data.data }
中dataList
作为键名 和res.data.data
,可以按需修改 和 按需取值,但整体格式必须按照这个规则来。
传参 与 接收参
页面间相互传值大家都很熟悉了, 以动态路由为例:
场景:A 页面 跳转至 B 页面 并 传递参数 Id
在 A 页面写如下代码,跳转至 B 页面:
this.$router.push('/B/12345)
在 B 页面接收参数并在 asyncData 中接收参数后请求数据:
asyncData(data){
return axios.post(url, {id: data.id}).then(res=>{
...
})
}
# 反向代理
- 安装
@nuxt.js/proxy
npm install --save @nuxt.js/proxy
- 配置文件
nuxt.config.js
里配置反向代理
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
'@nuxtjs/axios',
// 引入反向代理
'@nuxtjs/proxy'
],
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
// 开启反向代理
proxy: true
},
proxy: {
'/api': {
target: 'http://xxx.xxx.xxx',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
看到 proxy
对象是不是很熟悉了,没错这里和 Vue
的配置内容是一致的。但写到这里有个问题:
我们手动点击页面去请求数据没有问题,配置了反向代理后 asyncData
可以跨域拿到数据,但加载页面时 asyncData
在服务器触发执行时 ,就会报错找不到路径。
思路:想要区分前后端请求,即前端请求时使用代理,在服务端请求时不使用代理。那该怎么配置呢?我们接着往下看:
解决方法也很简单,在 nuxt
框架中有个全局变量 proccess.server
值为布尔类型。为 true
时标明是在服务端,否则是在客户端。这样我们可根据不同值来写对应的请求地址即可,完美解决。
# 配置使用 Element UI
- 安装
element ui
npm install --save element-ui
- 在
plugins
文件夹 创建element-ui.js
文件,内容如下
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Element, { locale })
- 修改配置文件
nuxt.config.js
引入element-ui
css: [
'element-ui/lib/theme-chalk/index.css'
],
plugins: [
'@/plugins/element-ui'
]
到此就在项目中引入了 element-ui
,具体使用和在 Vue 中完全一样,是不是很简单呀。
赶紧动起手来试试吧,欢迎你评论~~~