53 lines
2.3 KiB
JavaScript
53 lines
2.3 KiB
JavaScript
import { useLocaleConfig } from '@vuepress/helper/client';
|
|
import { useElementSize, useWindowScroll, useWindowSize } from '@vueuse/core';
|
|
import { computed, defineComponent, h, onMounted, shallowRef, Transition, } from 'vue';
|
|
import { usePageFrontmatter } from 'vuepress/client';
|
|
import '../styles/back-to-top.css';
|
|
export const BackToTop = defineComponent({
|
|
name: 'BackToTop',
|
|
setup() {
|
|
const pageFrontmatter = usePageFrontmatter();
|
|
const locale = useLocaleConfig(__BACK_TO_TOP_LOCALES__);
|
|
const body = shallowRef();
|
|
const { height: bodyHeight } = useElementSize(body);
|
|
const { height: windowHeight } = useWindowSize();
|
|
/** Scroll distance */
|
|
const { y } = useWindowScroll();
|
|
/** Whether to display button */
|
|
const show = computed(() => pageFrontmatter.value.backToTop !== false &&
|
|
y.value > __BACK_TO_TOP_THRESHOLD__);
|
|
const progress = computed(() => (y.value / (bodyHeight.value - windowHeight.value)) * 100);
|
|
onMounted(() => {
|
|
body.value = document.body;
|
|
});
|
|
return () => h(Transition, { name: 'back-to-top' }, () => show.value
|
|
? h('button', {
|
|
'type': 'button',
|
|
'class': 'vp-back-to-top-button',
|
|
'aria-label': locale.value.backToTop,
|
|
'onClick': () => {
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
},
|
|
}, [
|
|
__BACK_TO_TOP_PROGRESS__
|
|
? h('span', {
|
|
'class': 'vp-scroll-progress',
|
|
'role': 'progressbar',
|
|
'aria-labelledby': 'loadinglabel',
|
|
'aria-valuenow': progress.value,
|
|
}, h('svg', h('circle', {
|
|
'cx': '26',
|
|
'cy': '26',
|
|
'r': '24',
|
|
'fill': 'none',
|
|
'stroke': 'currentColor',
|
|
'stroke-width': '4',
|
|
'stroke-dasharray': `${Math.PI * progress.value * 0.48} ${Math.PI * (100 - progress.value) * 0.48}`,
|
|
})))
|
|
: null,
|
|
h('div', { class: 'back-to-top-icon' }),
|
|
])
|
|
: null);
|
|
},
|
|
});
|