由于公司的项目要考虑SEO,所以采用了NUXT来做服务端渲染。前后写了三个NUXT项目,遇到不少坑,这里记录一下填坑的过程和心得。
1.浏览器返回后,回到历史浏览位置(缓存页面数据)
现象:
在写NUXT项目的时候,发现返回之后无法回到历史浏览位置,但是页面会留在一个特定的位置。检查后发现,页面中用了无限滚动,无限滚动后加载的内容在返回之后就消失了。
原因:
asyncData等钩子函数在返回之后依然会触发,导致页面的数据在返回后重新加载了,所以之前无限滚动加载的数据都被重置了
解决方案:
先说基本思路:浏览过的页面保持活跃不被销毁,这样返回时组件的状态都还保持着离开时的样子,并且mounted等钩子函数不会再次触发,但asyncData函数无法被禁止,所以我们需要判断当前的执行环境,只有当执行环境是服务端时(也就是用户进入网站浏览的第一个页面)我们使用asyncData初始化数据,在客户端环境时(浏览器环境)我们使用mounted钩子来初始化数据,所以我们除了需要判断当前执行环境外,还要判断当前是否是第一个页面(第一个页面时mounted的初始化代码不触发,放在asyncData中触发);接下来上代码
首先使用keep-alive保持组件不被销毁,并使浏览器返回后,mounted等钩子函数不再触发
使用了keep-alive后,组件会添加activated和deactivated钩子,并且只有这两个钩子会在进入和离开页面时触发,mounted等钩子都不会再触发
<nuxt keep-alive />然后在asyncData中判断当前执行环境,如果是服务端环境则触发初始化代码,否则不触发
async asyncData({app,store:{state}}){
if(process.client) return;
// 初始化代码 .......
}客户端环境下,使用mounted来获取服务端数据初始化页面,这里需要一个字段来判断mounted是否需要执行初始化代码,在VUEX中添加is_serve_page属性。使用一个公共函数在mounted中执行,该函数判断初始化代码是否执行
// 客户端初始化页面数据
inject("clientInitPage", (callback, data) => {
if (state.is_serve_page) {
commit("setServePage", false);
} else {
callback && (data ? callback(data) : callback());
}
});在页面组件的mounted中执行clientInitPage
mounted(){
this.$clientInitPage(this.initPage);
}这样问题就解决了。
2.特殊的URL结构处理
为了更加友好的SEO,URL的目录结构和长度越短越好,我的项目中采用的详情页URL为”/post-123“和"/u-111",一个是帖子详情页,一个是用户详情页。这种的URL需要一个动态路由来处理。
- 在pages目录下,新建"_path.vue"文件。
- 在_path.vue中,根据URL的前缀来判断当前是什么页面,并获取相应的数据。
这里遇到一个坑,详情页之间切换的时候,页面会先显示第一个加载的详情页的数据,然后才会变成新的数据。原因是客户端执行的时候,会加载组件的mounted,在mounted数据加载出来之前,_path.vue中的数据会被当成props传过去,所以在客户端环境下,要重置_path.vue中的数据
// 根据url信息来选择显示相应的组件
<div class="path-page">
<uIndex v-if="page_name=='u'" :page_data="page_data" />
<postIndex v-else-if="page_name=='post'" :page_data="page_data" />
</div>
// 获取URL上的页面信息,并加载相应的数据
async asyncData({ app, store: { state }, params }) {
const PAGENAME = params.path.split("-")[0];
const PAGEID = params.path.split("-")[1];
// 客户端环境重置page_data和page_name
if (process.client) {
return {
page_data: null,
page_name: PAGENAME
};
}
let page_data = await getPageData(PAGENAME, PAGEID, app);
return {
page_data: page_data,
page_name: PAGENAME
};
}
// 获取页面数据
async function getPageData(PAGENAME, PAGEID, app) {
switch (PAGENAME) {
// 用户中心
case "u": {
return await getUPage(app, PAGEID);
break;
}
// 帖子详情
case "post": {
return await getPostPage(app, PAGEID);
break;
}
default:
break;
}
}
到这里,_path.vue就处理完毕了。服务端环境下页面的初始化放在_path.vue中获取,在客户端环境下,只需要在各自的组件mounted中获取就行了。
3. 添加谷歌百度等统计代码
做SEO肯定少不了添加各个搜索引擎的统计代码,统计代码只需要在生产环境中执行,所以这里把统计代码封装成函数,在页面初始化的时候加载。
1. 谷歌统计
在plugins中新建ga.js文件
export default ({ app: { router } }, inject) => {
// 谷歌统计分析
inject("googleAnalytics", _ => {
/* ** 只在生产模式的客户端中使用 */
if (process.client && process.env.NODE_ENV === "production") {
/* ** Google 统计分析脚本 */
(function(i, s, o, g, r, a, m) {
i["GoogleAnalyticsObject"] = r;
(i[r] =
i[r] ||
function() {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
"script",
"https://www.google-analytics.com/analytics.js",
"ga"
);
/*
** 当前页的访问统计这里写上自己网站的UA编码
*/
ga("create", "UA-*****-*", "auto");
/*
** 每次路由变更时进行pv统计
*/
router.afterEach((to, from) => {
/*
** 告诉 GA 增加一个 PV
*/
ga("set", "page", to.fullPath);
ga("send", "pageview");
});
}
});};2.百度统计
一样在plugins中新建bg.js
export default ({ app: { router } }, inject) => {
// 百度分析
inject("baiduAnalytics", _ => {
/*
** 只在生产模式的客户端中使用
*/
if (process.client && process.env.NODE_ENV === "production") {
/*
** baidu 统计分析脚本
*/
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?**********";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
/*
** 每次路由变更时进行pv统计
*/
router.afterEach((to, from) => {
/* 告诉百度增加一个PV */
try {
window._hmt = window._hmt || [];
window._hmt.push(["_trackPageview", to.fullPath]);
} catch (e) {}
});
}
});};然后在plugins中创建init.js文件,用作网站初始化的文件
export default ({ app }) => {
// 加载谷歌分析代码
app.$googleAnalytics();
// 加载百度分析代码
app.$baiduAnalytics();};
}最后在nuxt.config.js中引入js文件
plugins: [
{ src: '~plugins/ga.js', ssr: false },
{ src: '~plugins/bd.js', ssr: false },
{ src: "~/plugins/init.js", ssr: false }
],统计的代码就算是加上了,在chrome的NETWORK中可以看到没次切换页面都会触发百度和谷歌的统计
总结
随手记录下,其实在开发中遇到过不少问题,很多都记不清了。持续更新吧,想起来的时候继续补上。