自建博客文章链接:http://www.heblogs.cn/articleDetails/60fa5c1eb69f2b0a1af6492b
众所周知 vue开发的SPA(单页应用)不利于搜索引擎的SEO优化。
Nuxt.js简单的说是Vue.js的通用框架,最常用的就是用来作SSR(服务器端渲染)。
SSR,最近很热的词,意为 Server Side Rendering(服务端渲染),目的是为了解决单页面应用的 SEO问题,搜索引擎无法抓取页面相关内容,也就是用户搜不到此网站的相关信息 对于一般网站影响不大,但是对于论坛类,内容类网站来说是致命的。
一、targe
nuxt.config.js 中target属性 server(默认)为动态渲染 static为静态页面
server常用于页面例如分页列表等
static 若动态渲染分页列表使用静态 会提前将动态路由渲染成静态
具体请参考官网文献:https://go.nuxtjs.dev/config-target
Deployment targets for Nuxt >= v2.13:
Type: string
Default: server
Possible values:
'server': For server side rendering
'static': For static sites
二、head
Nuxt.js允许您使用head属性在nuxt.config.js文件中定义应用程序的所有默认标签。这对于添加用于SEO的默认标题和描述标签或设置视口或添加收藏夹图标非常有用。
具体参考官网文献:https://go.nuxtjs.dev/config-head
1.全局须在nuxt.config.js中配置
#在根目录nuxt.config.js内写下以下参数配置
head: {
title: 'website title',
meta: [
{
charset: 'utf-8' },
{
name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',name: 'description', content: 'my website description'}
],
link: [{
rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
}
2.局部在vue文件使用head作为一个对象来设置标题和描述仅用于当前
<template>
<div>my page</div>
</template>
<script>
export default {
head() {
return {
title: 'my website title',
meta: [
{
hid: 'description',
name: 'description',
content: 'Home content'
}
]
}
}
}
</script>
三、修改IP和端口号
#在根目录的Package.json文件里面修改IP和端口号
"config": {
"nuxt": {
"host": "0.0.0.0",
"port": "19003"
}
}
四、去除window.__nuxt=
问题:相信很多同学都会碰到这个问题 被产品爸爸追着喊着要去掉这段话 其实这段话是nuxt源文件中自渲染出来的 里面都是一些store的数据
方法一:修改渲染页面的源代码(来源网络)
参考文献(全网的关于删除window.__nuxt的文章几乎都是抄袭他的 他是原po):https://blog.csdn.net/qq_21916259/article/details/92791216
#修改文件路径: \node_modules\@nuxt\vue-renderer\dist\vue-renderer.js
//注释代码 禁止在页面初始化时添加window.__NUXT__代码
APP += `<script>${
serializedSession}</script>`;
// 注释代码2 禁止在页面路由改变时更新window.__NUXT__代码
hash.update(serializedSession);
cspScriptSrcHashes.push(`'${
csp.hashAlgorithm}-${
hash.digest('base64')}'`);
使用后:结果证明 是有效的 。但是如果两端代码一起注释 会导致异步渲染的动态新闻也会不出现在网页源代码中 。其实只要注释代码1就会禁止渲染window_nuxt_了 ,但是当我以为我成功要上传代码才发现,在我们公司 node_modules是不能上传的(相信大多数同学都是)。
方法二:在hooks中使用vue-renderer:ssr:contex(来源知乎)
参考文献:https://www.zhihu.com/question/430049651
hooks: {
'vue-renderer:ssr:context'(context) {
const routePath = JSON.stringify(context.nuxt.routePath)
context.nuxt = {
serverRenderer: true, routePath }
}
},
使用后:结果证明 是有效的 会将window_nuxt_极致的压缩成只有一点 但是很遗憾的是 异步渲染的动态新闻也会不出现在网页源代码中 所以放弃使用该方案
方法三:在hooks中使用插件cheerio辅助删除window_nuxt_js标签
#npm install cheerio -s
hooks: {
'render:route': (url, result) => {
// window.__nuxt__位于body中的第一个script中 移除了body中第一个脚本标签
this.$ = cheerio.load(result.html, {
decodeEntities: false })
this.$(`body script`).eq(0).remove()
result.html = this.$.html()
},
},
使用后:结果证明 是有效的 会将window_nuxt_所在的js标签删除 仅仅是删除标签 异步渲染的动态新闻也会保留 貌似store数据会失效 但是同学们要好好想想window_nuxt_里面装的就是store数据
五、asyncdata fetch
fetch(Nuxt 2.12+):该挂钩可以放置在任何组件上,并提供用于渲染加载状态(在客户端渲染期间)和错误的快捷方式。
asyncData:该挂钩只能放在页面组件上。与不同的是fetch,此钩子不会在客户端渲染期间显示加载占位符:相反,此钩子会阻止路由导航,直到它解决为止,如果失败,则会显示页面错误。
具体参考官网文献:
fetch:https://nuxtjs.org/docs/2.x/features/data-fetching
asyncdata:https://nuxtjs.org/docs/2.x/features/data-fetching#async-data
需求:产品要求异步获取的新闻详情需要在查看网页源代码时能够查看 很显然 在正常的vue路由钩子中获取的异步数据并不能直接的显现在源代码中
解决:这时候就需要使用这两个方法 我使用的是asyncdata,asyncdata方法会组件(仅限页面组件)每次加载之前会被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为页面的上下文对象,你可以利用asyncdata来获取数据并返回给当前组件
async asyncData(context) {
const {
data } = await getArticleDetails(context.params.id)
return {
details: data }
},
六、_id.vue文件配合watchQuery
需求:在新闻详情页正常获取新闻数据后 并且查看网页源代码能正常查看新闻数据,但是用户一但再次刷新将无法获取新闻数据
解决:在nuxt中动态路由需要写成 _id.vue(id为你的参数名字 可更改)并使用watchQuery箭头params变化
#在news文件index.vue中跳转 params跳转
<nuxt-link :to="`detail/${news.id}`">
跳转详情页
</nuxt>
#在detail文件_id.vue中接收 并使用watchQuery监听params中的id变化
#watchQuery监听到params变化 会自动执行asyncData方法 否则刷新并不会执行asyncData
async asyncData(context) {
const {
data } = await getArticleDetails(context.params.id)
return {
details: data }
},
watchQuery: ['id'],
七、error.vue
需求1:在用户输入路由错误(即非router配置的路由)时,响应一个错误的提示页面而不是使用浏览器报错的形式,如:输入 /a(a页面不存在) 能跳转到error页面
需求2:用户在新闻详情页内输入不存在的参数 跳转error页面并提示页面不存在
解决:建立错误页面 在根目录下的layouts文件夹下建立一个error.vue文件,它相当于一个显示应用错误的组件。
#在layouts文件夹下建立error.vue
<template>
<div>
<h2 v-if="error.statusCode == 404">页面不存在</h2>
<h2 v-else-if="error.statusCode == 500">文章不见了</h2>
<h2 v-else>网络异常 请返回刷新重试</h2>
<nuxt-link to="/">HOME</nuxt-link>
</div>
</template>
但是此文件只能保证路由不存在时调准啊404 既完成了需求1 那么 需求2呢??这个时候就要对第五点进行补充了 其实在asyncdata中 一定要用catch返回异常 那么怎么返回呢
async asyncData(context) {
try {
const {
data } = await getArticleDetails(context.params.id)
if (data) {
return {
details: data }
} else {
// 如果文章获取不到 那么后台返回为空未报错 context.error
context.error({
statusCode: 500 })
}
} catch (error) {
// 如果后台报错 context.error
context.error({
statusCode: 500 })
}
},
八、引入路径
强烈建议引入文件时 用~绝对路径获取 不要使用相对地址 可以使代码增强可阅读性
import {
getArticleDetails } from '~/api/news' //good
import {
getArticl } from '../../../api/news' // bad
九、引入插件
问题:引入插件会引发window找不到或者docment找不到
解决:引入插件需要按照nuxt的格式来引入 拿element举例
#在根目录plugins下创建element-ui.js 并定义它
import Vue from 'vue'
import {
Row
} from 'element-ui'
Vue.use(Row)
#在nuxt.config.js中引用
plugins: [
{
src: '@/plugins/element-ui', ssr: true },
],
这里需要声明下(swiper等其他插件亦如是)
如果你的网站是静态网站 ssr需要设置成false 使element只会在客户端渲染
如果使动态网站 则需要设置成true 否则element组件不会被服务端解析
这里我就爬过坑 静态网站中el-row和swiper组件正常 但是动态中 el-row和swiper无法被解析
#正常被解析
<div class="el-row"></div>
<div class="swiper"></div>
#未获取docmnet/winodw
<el-row></el-row>
<swiper></swiper>
好的 以上使用nuxt开发以来总结的几个小点 以及几个坑位,你们看完文章的小伙伴现在爬出坑了吗?