2
头图

foreword

In "An article that takes you to build a blog with VuePress + Github Pages" , we used VuePress to build a blog. Check the final effect: TypeScript Chinese document .

VuePress will add an anchor link to the left of each title:

After clicking the link becomes:

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

At this point, when you refresh the page, you will find that the page cannot be correctly positioned to the anchor point, and when you open the developer tools, you will see an error:

How to solve this problem?

wrong location

Since the code is compressed and obfuscated online, it is not easy to troubleshoot. We run the project locally and check the error message:

You can see that the error comes from vuerepss-plugin-smooth-scroll , we click to view the specific source code:


It can be seen that the error is from the document.querySelector(to.hash) , why is the error reported here?

This is because for each title, VuePress generates a DOM structure like this:

I can see h2 label id is named hash value, the hash if we are pure English, and there is no problem, but now we have the hash in Chinese, because the Chinese are encoded, document.querySelector error.

Official program

This problem is so easy to reproduce and so obvious, I think someone must have raised an issue, check the VuePress issue, and you can see that on October 3, 2020, someone raised PR and merged.

Then why is it still giving an error?

If we remove the reco theme we are currently using, we will find that the page will not report an error, but it still cannot locate the anchor point.

In fact, our error came from the vuerepss-plugin-smooth-scroll plugin reco

community program

That's it, then search to see if other people have encountered this problem, you can find such a scheme :

Create a new docs/.vuepress/theme/layouts/Layout.vue file and write the code:

<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>

After use, the page will not report an error, but you will find that all styles are lost, because using this method is equivalent to creating a new theme, and vuePress has switched to our custom theme.

However, VuePress provides the theme to inherit , create a new docs/.vuepress/theme/index.js , and write the code:

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

The style has been restored, but because we used the reco theme originally, and now we have changed it to inherit the vuepress default theme, some functions brought by the reco theme are all lost. Can we inherit the reco theme?

The answer is no, this is in the "Theme Inheritance" chapter of the 161f919c34ea9d VuePress official document:

Theme inheritance currently does not support higher-order inheritance, that is, a derived theme cannot be inherited.

So in order to solve this solution, it is necessary to give up the reco theme, and give up the reco theme, and there will be no error...

Then let's change the plan.

Do it yourself

Let it be done, I will solve it myself.

To sort out the current problems, when visiting links with Chinese anchors:

  1. The page has an error, and the error comes from the reco theme used by the vuepress-plugin-smooth-scroll theme.
  2. Can't jump to the anchor position normally

The simplest and rude way to report an error on the page is to modify the source code. We open node_modules/vuepress-plugin-smooth-scroll/lib/enhanceApp.js and modify it directly:

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

Because we do not submit the source code, but submit the compiled files to the server, changing the dependent source code has no effect.

The next step is to jump to the anchor position after the page is loaded. Before, we were in "VuePress Blog Optimization: Adding Data Statistics Function" , in enhanceApp.js to monitor the routing change, we can also monitor the ready event of the route, and then jump to Directly, we modify the code in .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);
  });
};

There is no direct access to the position of the title DOM element, and then use window.scrollTo jump. This is because under the reco , as the user continues to browse, the routing is also constantly switching, and the directory on the right will follow. Change, the click operation of the right directory is directly simulated here, and it is also to hand over the specific jump behavior to reco .

series of articles

The blog building series is the only series of practical tutorials I have written so far. It is expected to be about 20 articles, explaining how to use VuePress to build and optimize blogs, and deploy them to GitHub, Gitee, private servers and other platforms. This article is the 20th article, the address of the whole series of articles: https://github.com/mqyqingfeng/Blog

WeChat: "mqyqingfeng", add Yu Yu's friends, and pull you into the front-end learning exchange group.

If there are any mistakes or inaccuracies, please be sure to correct me, thank you very much. If you like or have inspiration, welcome to star, which is also an encouragement to the author.


冴羽
9.3k 声望6.3k 粉丝

17 年开始写前端文章,至今 6 个系列,上百篇文章,全网千万阅读