因爲公司的項目要考慮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中能夠看到沒次切換頁面都會觸發百度和谷歌的統計
總結
隨手記錄下,其實在開發中遇到過很多問題,不少都記不清了。持續更新吧,想起來的時候繼續補上。