tauri学习(2)-a链接伪类visited失效问题

December 09, 2023
测试
测试
测试
测试
6 分钟阅读

接上节继续,在前端开发中,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

继续阅读

更多来自我们博客的帖子

如何安装 BuddyPress
由 测试 December 17, 2023
经过差不多一年的开发,BuddyPress 这个基于 WordPress Mu 的 SNS 插件正式版终于发布了。BuddyPress...
阅读更多
Filter如何工作
由 测试 December 17, 2023
在 web.xml...
阅读更多
如何理解CGAffineTransform
由 测试 December 17, 2023
CGAffineTransform A structure for holding an affine transformation matrix. ...
阅读更多