越來越多的網(wǎng)站(zhàn),開始采用(yòng)"單頁(yè)麵結構(gòu)"(Single-page application)。
整(zhěng)個網站(zhàn)隻有一張網頁(yè),采用Ajax技術,根據(jù)用戶的(dí)輸(shū)入(rù),加(jiā)載(zǎi)不(bù)同(tóng)的內(nèi)容。
這種做法的好(hǎo)處是用(yòng)戶體驗好,節(jié)省流量,缺(quē)點是AJAX內容(róng)無法(fǎ)被(bèi)搜(sōu)索引擎抓(zhuā)取。舉例(lì)來(lái)說,你(nǐ)有一個(gè)網站(zhàn)。
http://example.com用戶通過(guò)井號(hào)結構的(dí)URL,看到不(bù)同的內(nèi)容(róng)。
http://example.com#1 http://example.com#2 http://example.com#3但(dàn)是,搜(sōu)索(suǒ)引擎隻(zhī)抓取example.com,不會(huì)理會井號,因此(cǐ)也就(jiù)無(wú)法索(suǒ)引(yǐn)內容。
為(wéi)了解決(jué)這(zhè)個問題(tí),Google提出了(liǎo)"井(jǐng)號+感(gǎn)嘆(tàn)號"的(dí)結構(gòu)。
http://example.com#!1當(dāng)Google發現上(shàng)麵這(zhè)樣(yàng)的URL,就(jiù)自動抓(zhuā)取另一個網址(zhǐ):
http://example.com/?_escaped_fragment_=1隻(zhī)要你(nǐ)把AJAX內容放(fàng)在(zài)這個網址,Google就(jiù)會收(shōu)錄(lù)。但是(shì)問(wèn)題(tí)是,"井(jǐng)號+感嘆號"非常難看且煩(fán)瑣(suǒ)。Twitter曾經采(cǎi)用這(zhè)種(zhǒng)結構,它把
http://twitter.com/ruanyf改成(chéng)
http://twitter.com/#!/ruanyf結(jié)果(guǒ)用(yòng)戶抱怨連連,隻用了半年(nián)就(jiù)廢除(chú)了(liǎo)。
那(nà)麼,有沒有什麼方法,可以在(zài)保(bǎo)持比(bǐ)較直(zhí)觀的URL的同(tóng)時,還讓(ràng)搜索引擎能夠抓(zhuā)取AJAX內容?
我一(yī)直以為沒有辦法做(zuò)到,直(zhí)到前(qián)兩天(tiān)看到(dào)了Discourse創(chuàng)始(shǐ)人(rén)之一(yī)的Robin Ward的解(jiě)決方(fāng)法(fǎ),不禁拍案叫絕。
Discourse是一個(gè)論(lùn)壇(tán)程序,嚴(yán)重(zhòng)依(yī)賴Ajax,但是又必須讓Google收(shōu)錄內容(róng)。它(tā)的(dí)解決(jué)方(fāng)法就是放(fàng)棄井(jǐng)號結構,采(cǎi)用 History API。
所謂 History API,指的(dí)是(shì)不刷(shuā)新頁(yè)麵(miàn)的(dí)情況(kuàng)下(xià),改變(biàn)瀏覽(lǎn)器(qì)地址欄顯示的URL(準(zhǔn)確(què)說(shuō),是改變(biàn)網(wǎng)頁的當(dāng)前(qián)狀(zhuàng)態)。這(zhè)裏有一(yī)個例(lì)子,你(nǐ)點擊上方的按鈕,開始播放音樂。然(rán)後,再(zài)點擊(jī)下(xià)麵的(dí)鏈(liàn)接(jiē),看看發生(shēng)了(liǎo)什麼(mó)事?
地址(zhǐ)欄(lán)的(dí)URL變(biàn)了(liǎo),但是(shì)音樂播(bō)放沒(méi)有中斷(duàn)!
History API 的詳(xiáng)細介紹,超出(chū)這篇文章的範(fàn)圍(wéi)。這裏隻(zhī)簡單(dān)說(shuō),它的(dí)作用就(jiù)是在(zài)瀏覽(lǎn)器的History對(duì)象中(zhōng),添(tiān)加一條(tiáo)記錄。
window.history.pushState(state object, title, url);上(shàng)麵這行(háng)命令(líng),可以讓(ràng)地(dì)址欄出現新的URL。History對(duì)象(xiàng)的pushState方法接受(shòu)三(sān)個參(cān)數,新(xīn)的URL就是第三個(gè)參數,前兩個(gè)參數(shù)都可(kě)以是null。
window.history.pushState(null, null, newURL);目前,各大瀏覽器都支持(chí)這個方(fāng)法:Chrome(26.0+),Firefox(20.0+),IE(10.0+),Safari(5.1+),Opera(12.1+)。
下(xià)麵就(jiù)是Robin Ward的(dí)方(fāng)法。
首(shǒu)先(xiān),用History API替代井號結(jié)構(gòu),讓(ràng)每個井(jǐng)號(hào)都變成(chéng)正(zhèng)常路(lù)徑(jìng)的URL,這(zhè)樣搜(sōu)索(suǒ)引擎就會(huì)抓取每(měi)一個(gè)網(wǎng)頁(yè)。
example.com/1 example.com/2 example.com/3然後,定義一(yī)個JavaScript函數,處理(lǐ)Ajax部(bù)分,根(gēn)據網址(zhǐ)抓取內容(假(jiǎ)定使(shǐ)用jQuery)。
function anchorClick(link) { var linkSplit = link.split('/').pop(); $.get('api/' + linkSplit, function(data) { $('#content').html(data); }); }再(zài)定義鼠(shǔ)標的(dí)click事件(jiàn)。
$('#container').on('click', 'a', function(e) { window.history.pushState(null, null, $(this).attr('href')); anchorClick($(this).attr('href')); e.preventDefault(); });
還要考慮到用戶(hù)點(diǎn)擊(jī)瀏覽器的"前(qián)進 / 後退"按(àn)鈕(niǔ)。這(zhè)時會(huì)觸發History對象(xiàng)的popstate事(shì)件。
window.addEventListener('popstate', function(e) { anchorClick(location.pathname); });
定義(yì)完(wán)上麵三(sān)段代碼,就能(néng)在不刷新(xīn)頁(yè)麵的情(qíng)況下,顯示正常路徑URL和(hé)AJAX內容。
最(zuì)後,設(shè)置(zhì)服(fú)務器(qì)端(duān)。
因為不使(shǐ)用(yòng)井號(hào)結(jié)構,每個(gè)URL都(dū)是(shì)一(yī)個(gè)不(bù)同的請(qǐng)求。所(suǒ)以,要(yào)求服務(wù)器端對(duì)所(suǒ)有這些請(qǐng)求,都(dū)返(fǎn)回如下結(jié)構的網頁,防止出(chū)現(xiàn)404錯誤(wù)。
<html> <body> <section id='container'></section> <noscript> ... ... </noscript> </body> </html>仔(zī)細(xì)看上麵這(zhè)段(duàn)代碼,你會發現有一個noscript標(biāo)簽(qiān),這就是(shì)奧(ào)妙所在。
我們把(bǎ)所有要(yào)讓(ràng)搜索引擎(qíng)收錄(lù)的(dí)內容(róng),都(dū)放在noscript標簽之中(zhōng)。這(zhè)樣的話,用戶(hù)依然可以(yǐ)執行AJAX操(cāo)作,不(bù)用刷新頁麵(miàn),但是(shì)搜(sōu)索引擎(qíng)會收(shōu)錄每個網(wǎng)頁的(dí)主(zhǔ)要內(nèi)容(róng)!
-- 阮一(yī)峰
轉(zhuǎn)載(zǎi)請保留原(yuán)文地址: https://antelcom.cn/show-395.html

