乐趣区

关于javascript:VuePress-博客优化之中文锚点跳转问题

前言

在《一篇带你用 VuePress + Github Pages 搭建博客》中,咱们应用 VuePress 搭建了一个博客,最终的成果查看:TypeScript 中文文档。

VuePress 会在每个题目左侧都加一个锚点链接:

点击后链接变为:

http://ts.yayujs.com/learn-typescript/handbook/TheBasics.html# 降级 -downleveling

此时刷新下页面,会发现,页面并不能正确的定位到锚点地位,而且关上开发者工具,还会看到报错:

那这个问题该怎么解决呢?

谬误定位

在线上因为代码都是压缩混同后的,不好排查,咱们在本地运行我的项目,而后查看报错信息:

能够看到谬误是来自于 vuerepss-plugin-smooth-scroll 这个插件中,咱们点击查看具体的源码:


能够看到,报错是来自于 document.querySelector(to.hash) 这句,为什么会在这里报错呢?

这是因为对于每一个题目,VuePress 都会生成这样一个 DOM 构造:

能够看到 h2 标签的 id 是以 hash 值命名的,如果咱们的 hash 是纯英文,并没有什么问题,然而当初咱们的 hash 中有中文,因为中文被编码,document.querySelector报错。

官网计划

这个问题这么容易复现,且这么显著,我想必定有人提了 issue,查看 VuePress 的 issue,能够看到在 2020 年 10 月 3 号就有人提了 PR,并且 merge 了。

那为什么还会报错呢?

如果咱们去掉咱们目前在用的 reco主题,咱们就会发现,页面并不会有报错,只不过仍然不能定位到锚点而已。

实际上,咱们的报错是来自于咱们应用的 reco 主题应用的 vuerepss-plugin-smooth-scroll 插件。

社区计划

那成吧,那搜寻看下其他人是否也遇到过这个问题吧,能够查到这样一个计划:

新建一个 docs/.vuepress/theme/layouts/Layout.vue文件,代码写入:

<script>
export default {
  methods: {scrollTo(selector) {if (!selector || selector === '#') return
      const el = document.querySelector(decodeURIComponent(selector))
      if (el && el.offsetTop) {window.scrollTo(0, el.offsetTop)
      }
    }
  },
  mounted() {this.scrollTo(location.hash)
  }
}
</script>

应用后,页面是不报错了,但会发现款式全副失落了,因为应用这种形式相当于新建了一个主题,vuePress 曾经改用咱们的自定义主题了。

不过 VuePress 提供了主题继承的性能,新建一个 docs/.vuepress/theme/index.js,代码写入:

module.exports = {extend: '@vuepress/theme-default'}

款式是复原了一些,然而因为咱们原本应用的是 reco 主题,当初改成了继承 vuepress 默认主题,reco 主题带来的一些性能就全失落了,那咱们能继承 reco 主题吗?

答案是不能,这在 VuePress 官网文档的「主题的继承」章节里有讲到:

主题继承临时不反对高阶继承,也就是说,一个派生主题无奈被继承。

所以为了解决这个计划,就要放弃 reco 主题,而放弃了 reco 主题,原本也不会有报错了……

那咱们换个计划吧。

本人入手

成吧成吧,我本人解决。

梳理下当下的问题,当拜访带中文锚点的链接时:

  1. 页面有报错,而报错来自于 reco主题应用的 vuepress-plugin-smooth-scroll主题。
  2. 不能失常跳转到锚点地位

页面报错这个问题最简略粗犷的形式就是批改源码了,咱们关上 node_modules/vuepress-plugin-smooth-scroll/lib/enhanceApp.js,间接批改:

const enhanceApp = ({Vue, router}) => {router.options.scrollBehavior = (to, from, savedPosition) => {
                // ...
        else if (to.hash) {
            //...
          
              // 加上 decodeURIComponent
            const targetElement = document.querySelector(decodeURIComponent(to.hash));
            
                        //...
        }
                // ...
    };
};

因为咱们并不会提交源码,而是提交编译后的文件到服务器上,所以改了依赖的源码也没有什么影响。

接下来是页面加载完跳转到锚点地位,之前咱们在《VuePress 博客优化之增加数据统计性能》,在 enhanceApp.js 中监听路由的扭转,同样咱们能够监听路由的 ready 事件,而后跳转到间接的地位,咱们批改下 .vuepress/enhanceApp.js中的代码:

export default ({router}) => {
    // ...
 
  router.onReady(() => {const { hash} = document.location;
    setTimeout(() => {if (hash.length > 1) {const id = decodeURIComponent(hash);
        const el = document.querySelector(`.reco-side-${decodeURIComponent(id).substring(1)}`);
        el.click();}
    }, 1000);
  });
};

在这里并没有间接获取题目 DOM 元素的地位,而后应用 window.scrollTo 跳转,这是因为在 reco 主题下,随着用户一直的浏览,其实路由也在不停的切换,右侧的目录才会随之扭转,这里间接模仿了右侧目录的点击操作,也是为了将具体跳转的行为交给 reco 来实现。

系列文章

博客搭建系列是我至今写的惟一一个偏实战的系列教程,预计 20 篇左右,解说如何应用 VuePress 搭建、优化博客,并部署到 GitHub、Gitee、公有服务器等平台。本篇为第 20 篇,全系列文章地址:https://github.com/mqyqingfeng/Blog

微信:「mqyqingfeng」,加冴羽好友,拉你进前端学习交换群。

如果有谬误或者不谨严的中央,请务必给予斧正,非常感激。如果喜爱或者有所启发,欢送 star,对作者也是一种激励。

退出移动版