From 0c0beefb00ffee160c776d7748768282aa6cbd88 Mon Sep 17 00:00:00 2001 From: BobChao87 Date: Thu, 26 Aug 2021 21:06:47 -0700 Subject: [PATCH] Scroll to top on nav, but not back/forward Related to Issue #32 --- layouts/default.vue | 5 +++++ nuxt.config.js | 1 + plugins/scroll.client.ts | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 plugins/scroll.client.ts diff --git a/layouts/default.vue b/layouts/default.vue index 22dc1982..8d9fcb08 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -16,6 +16,11 @@ export default Vue.extend({ head(): Required> { return this.$nuxtI18nHead({ addSeoAttributes: true }); }, + watch: { + $route(): void { + this.$scroll(); + }, + }, mounted(): void { // Provide calls to this.$gtag here to update Analytics }, diff --git a/nuxt.config.js b/nuxt.config.js index c5d2d5b6..cf7b247d 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -33,6 +33,7 @@ export default { // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins 'plugins': [ { src: '~/plugins/google-gtag.client.ts', mode: 'client' }, + { src: '~/plugins/scroll.client.ts', mode: 'client' }, ], // Auto import components: https://go.nuxtjs.dev/config-components diff --git a/plugins/scroll.client.ts b/plugins/scroll.client.ts new file mode 100644 index 00000000..e62f2e7b --- /dev/null +++ b/plugins/scroll.client.ts @@ -0,0 +1,40 @@ +import { Plugin } from '@nuxt/types'; + +declare module 'vue/types/vue' { + interface Vue { + $scroll(): void; + } +} + +/** + * How does this work? A good question. It may be buggy. + * + * When user navigation occurs, history is written to the browser to be used by + * the back/forward buttons. This history maintains an immutable state for each + * page. We are referencing one of the values of that state stack, the key. In + * Chrome and Firefox, this /appears/ to be a monotonically increasing + * string-encoded number. Possibly the number of milliseconds since the + * page/website was first navigated to. More testing is required. + * + * We detect when the value on the page we're on is higher than the largest + * value we've seen before. If it is, it's a new page, and we scroll. If it's + * not, we rely on the user's browser settings to decide to scroll to their + * previous position or not, depending on preferences. + * + * This function is called universally by watching to see when $route changes + * in the layout for the pages. If it's broken, first confirm your page's + * layout does call this.$scroll() inside of watch on $route. + */ +const scrollPlugin: Plugin = (_, inject) => { + let historyKeyMax = 0; + + inject('scroll', () => { + const historyKey = +history.state.key; + if (historyKeyMax < historyKey) { + historyKeyMax = historyKey; + window.scrollTo(0, 0); + } + }); +}; + +export default scrollPlugin;