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 }
}
在应用程序上单击 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 }
}