nuxt 利用時、URLに hash ( #hoge ) を設定すると同時に、スムーズにするロールするを行いたい場合、一般の方が書いた記事には、to をカラにすればいいと書いてありますが、正しく動作しない条件が存在します。
<div id="note"></div>
<nuxt-link to v-scroll-to="'#note'">noteクリック</nuxt-link>
<div id="memo"></div>
<nuxt-link to v-scroll-to="'#memo'">memoクリック</nuxt-link>
このように記載した上で、URLにハッシュを設定しブラウザをリロード。この状態で、nuxt-link をクリックすると、window.pageYOffset が 0 が入り、スクロール開始位置が間違っているため、とくにスクロール方向が逆になった時に違和感が大きくなってしまいます。フッターに # がついたリンクがあると特に発生しやすいはずです。
vue-scrollto や smooth-scroll が悪いわけではなく、
初回表示時にnuxt-linkをクリックすると、nuxt-link がまず pageYOffset = 0 にスクロール設定することが原因でした。
その後スクロールが開始するため、正し位置からスクロールしません。
対処するためには、以下のように、nuxt-link 代わりの component を作るのがよいのではないでしょうか。
<template lang="pug">
a(:href="to" @click.stop="onClick")
slot
</template>
<script lang="typescript">
import {
defineComponent,
getCurrentInstance
} from '@nuxtjs/composition-api'
import TWEEN from '@tweenjs/tween.js'
type Props = {
path: string,
hash: string | null,
anker: string,
}
export default defineComponent({
props: {
path: {
required: true,
type: String
},
hash: {
type: String
},
anker: {
required: true,
type: String
}
},
setup ({ path, hash, anker }: Props, { emit }) {
const current = getCurrentInstance()
const scrollTo = (anker: string) => {
const dom = document.querySelector(anker)
if (!dom) { return }
const end = dom.getBoundingClientRect().top + window.pageYOffset
// tween.js の例
const data = { y: window.pageYOffset }
new TWEEN.Tween(data)
.to({ y: end }, 500)
.easing(TWEEN.Easing.Exponential.InOut)
.onUpdate(() => { window.scrollTo({ top: data.y }) })
.start()
const animate = (time: number) => {
if (TWEEN.update(time)) {
requestAnimationFrame(animate)
}
}
animate(0)
}
const to = hash === undefined ? `${path}${anker}` : `${path}${hash}`
const onClick = () => {
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) {
// do nothing
} else
if (current?.$route.path === path) {
e.preventDefault()
window.history.replaceState(null, '', to)
scrollTo(anker)
} else {
e.preventDefault()
current?.$router.push(to)
}
}
return {
to,
onClick
}
}
})
</script>