接上節繼續,在前端開發中,a鏈接常用a:visited僞類,用於區分鏈接點擊過後的呈現效果。
在tauri項目模板中,把App組件中添加3個鏈接:
然後在App.css中添加幾個樣式:
程序跑起來後,卻意外發現:其它幾個僞類都起作用,唯獨:visited這個僞類,在tairu桌面應用中一點反應都沒有,參見下面,上面爲tauri桌面應用,下面爲瀏覽器窗口。
從動圖效果看出,在瀏覽器中:visited是能正常生效的,點擊後的鏈接顯示爲orange橙色,但是在上面的tauri應用中卻沒反應。其實不光是tauri有這個問題,electron同樣也有類似問題。
StackOverFlow上有外國網友給出瞭解決思路:將訪問過的鏈接,寫入localStorage中,然後在組件生命週期的DidUnmount中,給這些鏈接,強行附加一個額外樣式。
先定義2個常量,分別用於localStorage存放訪問過的a鏈接記錄,另1個則是強行附加的樣式類名
const LOCAL_STORAGE_HISTORY_KEY = "visitedHistory"; const VISITED_CLASS_NAME = "visited";
核心代碼1:setVisited
從localStorage中取出點擊過的a鏈接記錄(先不管如何存入localStorage的,後面會講到,假如已經有了),然後判斷記錄是否過期,如果過期了則刪除(重要!否則一直不停點,一直不停向localStorage中存,列表越來越大,早晚崩潰),然後將每個a鏈接的href跟訪問記錄匹配,對上了,則追加1個visited的樣式(當然:這個樣式要額外寫)
/** * 根據localStorage裏的歷史記錄,將a附加上visited樣式 * by 菩提樹下的楊過http://yjmyzz.cnblogs.com/ */ function setVisited() { let localstorageSimuHistory = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY); let simuHistory = localstorageSimuHistory ? JSON.parse(localstorageSimuHistory) : []; //過期訪問記錄清理 const now = new Date(); let hasExpired = false; for (let i = simuHistory.length - 1; i >= 0; i--) { let item = simuHistory[i]; //過期的訪問記錄刪除 if (now.getTime() > item.expire) { simuHistory.splice(i, 1) hasExpired = true } } if (hasExpired) { if (simuHistory.length <= 0) { localStorage.removeItem(LOCAL_STORAGE_HISTORY_KEY); } else { localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(simuHistory)); } } //遍歷所有a,訪問過的,則強制附加visited樣式 let elements = document.getElementsByTagName('a'); for (let i = 0; i < elements.length; i++) { for (let h = 0; h < simuHistory.length; h++) { if (elements[i].href === simuHistory[h].url && elements[i].className.indexOf(VISITED_CLASS_NAME) === -1) { elements[i].className += ` ${VISITED_CLASS_NAME}`; } } } }
localStorage中的數據,大致長這樣:
核心代碼2:addHref
每個鏈接點擊後,將自身的href存入localStorage
/** * a鏈接點擊後將url加入localStorage * @param url */ function addHref(url: String) { let localstorageSimuHistory = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY); let simuHistory = localstorageSimuHistory ? JSON.parse(localstorageSimuHistory) : []; let found = false; const now = new Date(); //訪問記錄過期時間設置(此處僅爲示例:30秒) const ttl: number = 1000 * 30; for (let i = simuHistory.length - 1; i >= 0; i--) { let item = simuHistory[i]; if (item.url === url) { found = true; //過期時間續租 simuHistory[i] = { "url": url, "expire": new Date().getTime() + ttl }; break; } } //如果本鏈接不在訪問列表裏,則添加 if (!found) { simuHistory[simuHistory.length] = { "url": url, "expire": new Date().getTime() + ttl }; localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(simuHistory)); } //此處只是爲了方便,把所有點過的a全刷了一把,還可以再優化下(略) setVisited(); }
核心代碼3:bindAddHref
給每個a鏈接的click綁定事件
function bindAddHref() { let elements = document.getElementsByTagName('a'); for (let i = 0; i < elements.length; i++) { elements[i].onclick = () => { addHref(elements[i].href); } } setVisited(); }
有了上面3個核心方法,就可以在App的生命週期"DidMount"掛載階段,調用bindAddHref,爲每個a鏈接自動綁定click事件
當然App.css裏得手動添加.visited樣式
.visited { color: orange !important }
最後運行的效果如下:
從運行效果上看,"大致"跟瀏覽器上的表現相同,但值得說明的是,這畢竟只是一種變相的解決方法,二者還是有差別的,如果用開發者工具,把localStorage清了,而瀏覽器並不清除緩存(反過來也一樣),二者的表現還是有差異,不過大多數情況下,上述解決方案,應該能滿足業務要求了。