Vue 路由器不滚动到正确的哈希位置

Vue Router not scolling to correct hash location

在应用程序上单击 link 时,路由器不会滚动到给定的正确哈希位置。但它确实很酷。滚动条在页面上总是高出大约 1 个元素。例如,如果我的页面是这样的:

<template>
    <div id="div1">Div1</div>
    <div id="div2">Div2</div>
    <div id="div3">Div3</div>
    <div id="div4">Div4</div>
</template>

然后,如果我单击一个 link 进入散列“div3”,它会将我滚动到 div2 的顶部。只有极少数 select 元素被正确滚动到。是否有一个原因?设置页边距?

路由器代码:

const router = new VueRouter({
  routes,
  mode: 'history',
  base: "/",
  scrollBehavior (to, from, savedPosition) {
    if (to.hash) {
        return {
          selector: to.hash,
          behavior: 'smooth',
        }
    } else {
        return { x: 0, y: 0 }
    }
  }
})

调用散列路由的代码示例:

if (item.title == "Mission") {
    router.push({name: 'Explore', hash: '#mission-statement'});
} else if (item.title == "Our Story") {
    router.push({name: 'Explore', hash: '#our-story-container'});
} else if (item.title == "Shared principles") {
    router.push({name: 'Explore', hash: '#shared-principles-container'});
} else if (item.title == "Volunteer Opportunities") {
    router.push({name: 'Explore', hash: '#volunteer-container'});
} else if (item.title == "Gallery") {
    router.push({name: 'Explore', hash: '#galleries'});
} else if (item.title == "Living") {
    router.push({name: 'Explore', hash: '#living-container'});
} else if (item.title == "Contact Us") {
    router.push({name: 'Explore', hash: '#contact-us-container'});
} else {
    router.push("/explore")
}

解决方案:

在 IVO GELOV 的回答的帮助下,我能够使用下面的代码更新滚动行为功能,并且一切正常。

scrollBehavior (to, from, savedPosition) {
    let position = {}
    if (to.hash) {
        position = {
          selector: to.hash,
          offset: { x: 0, y: 100 },
          behavior: 'smooth',
        }
    } else {
        position = { x: 0, y: 0 }
    }
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(position)
      }, 100)
    })
  }

Nuxt.js 在其 ./nuxt/router.js 中使用了以下代码 - 也许您可以将其应用到您的用例中:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router) 

if (process.client) {
  window.history.scrollRestoration = 'manual'
}
const scrollBehavior = function (to, from, savedPosition) {
  // if the returned position is falsy or an empty object,
  // will retain current scroll position.
  let position = false

  // if no children detected
  if (to.matched.length < 2) {
    // scroll to the top of the page
    position = { x: 0, y: 0 }
  } else if (to.matched.some((r) => r.components.default.options.scrollToTop)) {
    // if one of the children has scrollToTop option set to true
    position = { x: 0, y: 0 }
  }

  // savedPosition is only available for popstate navigations (back button)
  if (savedPosition) {
    position = savedPosition
  }

  return new Promise(resolve => {
    // wait for the out transition to complete (if necessary)
    window.$nuxt.$once('triggerScroll', () => {
      // coords will be used if no selector is provided,
      // or if the selector didn't match any element.
      if (to.hash) {
        let hash = to.hash
        // CSS.escape() is not supported with IE and Edge.
        if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') {
          hash = '#' + window.CSS.escape(hash.substr(1))
        }
        try {
          if (document.querySelector(hash)) {
            // scroll to anchor by returning the selector
            position = { selector: hash }
          }
        } catch (e) {
          console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).')
        }
      }
      resolve(position)
    })
  })
}

export function createRouter () {
  return new Router({
    mode: 'history',
    base: '/',
    linkActiveClass: 'nuxt-link-active',
    linkExactActiveClass: 'nuxt-link-exact-active',
    scrollBehavior,
    routes: [ .... ],
    fallback: false
  })
}

一个示例实现(取自 https://dev.to/dimer191996/nuxt-js-smooth-scrolling-with-hash-links-94a)- 如果您的 <router-view> 包含在 <transition> 中,您可能还需要设置 window.history.scrollRestoration = 'manual':

scrollBehavior: async (to, from, savedPosition) => {
      if (savedPosition) {
        return savedPosition
      }

      const findEl = async (hash, x) => {
        return document.querySelector(hash) ||
          new Promise((resolve, reject) => {
            if (x > 50) {
              return resolve()
            }
            setTimeout(() => { resolve(findEl(hash, ++x || 1)) }, 100)
          })
      }

      if (to.hash) {
        let el = await findEl(to.hash)
        if ('scrollBehavior' in document.documentElement.style) {
          return window.scrollTo({ top: el.offsetTop, behavior: 'smooth' })
        } else {
          return window.scrollTo(0, el.offsetTop)
        }
      }

      return { x: 0, y: 0 }
    }