使用 Aplayer 导致博客目录跳转失效

问题

可以在此链接中测试 https://codepen.io/wangriyu/full/aGraGO

加载 1.10.1 版本的 Aplayer 后,页面内带中文字符的锚标签均无法跳转,而纯英文的正常

前因

toc

前不久的某一天,我照常打开博客浏览新发布的文章时,点击侧边栏的锚标签进行目录跳转,突然发现没反应!?

emoji

难道是我打开的姿势不对?我又打开另几篇博客,试了几个目录发现都一样没反应,难道是我之前给左上角背景图片添加 pointer-events: none 时影响到侧边栏的点击事件了?

但是也不对啊,我试了发现只有中文标题的目录点击跳转不了,英文标题却是正常的,肯定是其他地方的锅

我的第一直觉是这个左下角的播放器,因为这是前不久添加的,而且离这些锚标签近

打开控制台,我先看了播放器是否覆盖了目录,没有!然后我看了下锚标签的点击事件

console

这个 smoothscroll 有点眼生啊,我好像没用过啊

我再试着把播放器去掉,发现目录跳转一切正常,果然是你的锅

后果

发现是播放器的问题之后,我继续找问题出在哪,我发现去掉播放器之后,锚标签的点击事件少了刚才的 smoothscroll,应该是这个插件的问题

console

先去 Aplayer 的仓库看了下依赖,果然使用这插件

smoothscroll

再去看了下 smoothscroll 的仓库,克隆了一份做了下测试

然后我发现它处理 hash 时只测试了英文,而使用中文时,中文字符转成了 Unicode 码,下面函数的判断条件无法成立,后面的点击处理也就失效了

var linkHandler = function(ev) {
    if (!ev.defaultPrevented) {
        ev.preventDefault();

        if (location.hash !== this.hash) window.history.pushState(null, null, this.hash)
        // using the history api to solve issue #1 - back doesn't work
        // most browser don't update :target when the history api is used:
        // THIS IS A BUG FROM THE BROWSERS.
        // change the scrolling duration in this call
        var node = document.getElementById(this.hash.substring(1))
        if (!node) return; // Do not scroll to non-existing node

        smoothScroll(node, 500, function (el) {
            location.replace('#' + el.id)
            // this will cause the :target to be activated.
        });
    }
}

需要修改的地方是对 hash 的进行 decodeURIComponent 处理,这样就能正常处理中文的标签和 location 的对应问题了

var linkHandler = function(ev) {
    if (!ev.defaultPrevented) {
        ev.preventDefault();

        if (decodeURIComponent(location.hash) !== decodeURIComponent(this.hash)) window.history.pushState(null, null, decodeURIComponent(this.hash))
        // using the history api to solve issue #1 - back doesn't work
        // most browser don't update :target when the history api is used:
        // THIS IS A BUG FROM THE BROWSERS.
        // change the scrolling duration in this call
        var node = document.getElementById(decodeURIComponent(this.hash).substring(1))
        if (!node) return; // Do not scroll to non-existing node

        smoothScroll(node, 500, function (el) {
            location.replace('#' + el.id)
            // this will cause the :target to be activated.
        });
    }
}

我已经提出了 pull request,静等官方修复

如果是使用 Aplayer 的用户,可以先自行修改依赖,重新编译一份带正常功能的 smoothscroll 的 Aplayer

我这有已经打包修复的: https://src.wangriyu.wang/lib/Aplayer/APlayer.min.js

现在我博客侧边栏的目录点击也是正常的了

文章目录
  1. 问题
  2. 前因
  3. 后果