因为公司的项目要考虑SEO,因此采用了NUXT来作服务端渲染。先后写了三个NUXT项目,遇到很多坑,这里记录一下填坑的过程和心得。vue
现象:chrome
在写NUXT项目的时候,发现返回以后没法回到历史浏览位置,可是页面会留在一个特定的位置。检查后发现,页面中用了无限滚动,无限滚动后加载的内容在返回以后就消失了。浏览器
缘由:缓存
asyncData等钩子函数在返回以后依然会触发,致使页面的数据在返回后从新加载了,因此以前无限滚动加载的数据都被重置了bash
解决方案:app
先说基本思路:浏览过的页面保持活跃不被销毁,这样返回时组件的状态都还保持着离开时的样子,而且mounted等钩子函数不会再次触发,但asyncData函数没法被禁止,因此咱们须要判断当前的执行环境,只有当执行环境是服务端时(也就是用户进入网站浏览的第一个页面)咱们使用asyncData初始化数据,在客户端环境时(浏览器环境)咱们使用mounted钩子来初始化数据,因此咱们除了须要判断当前执行环境外,还要判断当前是不是第一个页面(第一个页面时mounted的初始化代码不触发,放在asyncData中触发);接下来上代码async
首先使用keep-alive保持组件不被销毁,并使浏览器返回后,mounted等钩子函数再也不触发函数
使用了keep-alive后,组件会添加activated和deactivated钩子,而且只有这两个钩子会在进入和离开页面时触发,mounted等钩子都不会再触发
<nuxt keep-alive />复制代码
而后在asyncData中判断当前执行环境,若是是服务端环境则触发初始化代码,不然不触发post
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);
}复制代码
这样问题就解决了。
为了更加友好的SEO,URL的目录结构和长度越短越好,个人项目中采用的详情页URL为”/post-123“和"/u-111",一个是帖子详情页,一个是用户详情页。这种的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中获取就好了。
作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中能够看到没次切换页面都会触发百度和谷歌的统计
总结
随手记录下,其实在开发中遇到过很多问题,不少都记不清了。持续更新吧,想起来的时候继续补上。