tauri學習(2)-a鏈接僞類visited失效問題

上節繼續,在前端開發中,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清了,而瀏覽器並不清除緩存(反過來也一樣),二者的表現還是有差異,不過大多數情況下,上述解決方案,應該能滿足業務要求了。

 

文中示例代碼:https://github.com/yjmyzz/tauri-visited-solution

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章