博客篇 -- Vurperss 优化中文锚点滚动定位问题
记录一下,禁用 vuepress-plugin-smooth-scroll 插件,并将插件内容移动到本地来解决中文锚点跳转失败的问题。
最近使用DocSearch (opens new window)实现全文搜索功能发现一个问题:
- 当页面锚点为中文时,每次点击锚点,不能实时滚动到锚点位置。
原因是:
- 插件 vuepress-plugin-smooth-scroll (opens new window) 在实现的过程中并未对中文路径做转码。
插件源码片段:
// 获取锚点,并跳转到锚点位置
const targetElement = document.querySelector(to.hash);
if (targetElement) {
return window.scrollTo({
top: getElementPosition(targetElement).y,
behavior: 'smooth',
});
}
由于插件是 npm 插件,不方便修改,所以就禁用了插件 vuepress-plugin-smooth-scroll (opens new window),并将插件内容移植到本地实现。
👉 感谢vuepress-plugin-smooth-scroll (opens new window)插件 👈
# Step 1 禁用插件
在 .vuepress/theme/index.js中,将插件禁用
plugins: [
// ...
'@vuepress-reco/back-to-top',
['vuepress-plugin-smooth-scroll', false]
// ...
]
# Step 2 实现 SmoothScroll 效果
# scrollBehavior 扩展
在 .vuepress/theme/helpers/other.js (或者新建JS文件)中实现 router.options 扩展。
export function RouterSmoothScroll(Vue, router) {
router.options.scrollBehavior = (to, from, savedPosition) => {
if (savedPosition) {
return window.scrollTo({
top: savedPosition.y,
behavior: 'smooth',
});
}
else if (to.hash) {
if (Vue.$vuepress.$get('disableScrollBehavior')) {
return;
}
const targetElement = document.querySelector(decodeURIComponent(to.hash));
if (targetElement) {
return window.scrollTo({
top: getElementPosition(targetElement).y,
behavior: 'smooth',
});
}
}
else {
return window.scrollTo({
top: 0,
behavior: 'smooth',
});
}
}
}
function getElementPosition(el) {
const docEl = document.documentElement;
const docRect = docEl.getBoundingClientRect();
const elRect = el.getBoundingClientRect();
return {
x: elRect.left - docRect.left,
y: elRect.top - docRect.top,
};
}
实际只是将原本的 querySelector 选择器中的 to.hash 进行 URL 转码。
// 找到以下代码并修改
const targetElement = document.querySelector(to.hash);
// 修改后
const targetElement = document.querySelector(decodeURIComponent(to.hash));
# smoothscroll 样式
在 .vuepress/theme/styles 文件夹下新建 smoothscroll.styl 文件。
html
scroll-behavior smooth
# smoothscroll 混入
在 .vuepress/theme/mixins 文件夹下新建 smoothscroll.js 文件。
混入 smoothscroll-polyfill页面平滑滚动插件。
import smoothscroll from 'smoothscroll-polyfill'
import '../styles/smoothscroll.styl'
export default {
mounted() {
smoothscroll.polyfill()
},
}
::: tips
此处只针对 Vuepress 博客设置,如需了解更多,点这里 (opens new window)
:::
# enhanceApp.js 引入
修改 .vuepress/theme/enhanceApp.js 主题入口文件。
import postMixin from '@theme/mixins/posts'
import localMixin from '@theme/mixins/locales'
import smoothscroll from '@theme/mixins/smoothscroll'
import { interceptRouterError, fixRouterError404, RouterSmoothScroll} from '@theme/helpers/other'
export default ({
Vue,
siteData,
isServer,
router
}) => {
Vue.mixin(postMixin)
Vue.mixin(localMixin)
Vue.mixin(smoothscroll)
RouterSmoothScroll(Vue, router)
interceptRouterError(router)
fixRouterError404(router)
}
# Step 3 重新启动
npm run dev
或
yarn dev