滚动行为 VueJS 无法正常工作
Posted
技术标签:
【中文标题】滚动行为 VueJS 无法正常工作【英文标题】:Scroll behaviour VueJS not working properly 【发布时间】:2019-06-29 08:33:02 【问题描述】:我正在尝试通过 VueJS 中的 scrollBehaviour 进行滚动以锚定。
一般来说,我用以下方式改变当前的路由器:
this.$router.push(path : 'componentName', name: 'componentName', hash: "#" + this.jumpToSearchField)
我的 VueRouter 定义为:
const router = new VueRouter(
routes: routes,
base: '/base/',
mode: 'history',
scrollBehavior: function(to, from, savedPosition)
let position =
if (to.hash)
position =
selector : to.hash
;
else
position = x : 0 , y : 0
return new Promise((resolve, reject) =>
setTimeout(() =>
resolve(position)
, 10)
)
);
我的路线:
[
path: '/settings/:settingsId',
component: Settings,
children: [
path: '',
name: 'general',
components:
default: General,
summary: Summary
,
path: 'tab1',
name: 'tab1',
components:
default: tab1,
summary: Summary
,
path: 'tab2',
name: 'tab2',
components:
default: tab2,
summary: Summary
,
path: 'tab3',
name: 'tab3',
components:
default: tab3,
summary: Summary
]
,
path: '/*',
component: Invalid
];
假设我在 tab1 组件上,我想跳转到 tab3 组件上的锚点“test”
router.push()
之后,我看到scrollBehavior
被触发,组件从 tab1 切换到 tab3 以及 URL 更改(例如 http:/ /localhost:8080/tab1 到 http://localhost:8080/tab3#test) 但窗口位置没有放置在锚点所在的位置,而只是在窗口的顶部。
当然,我在 tab3 组件上有带有 id="test" 的 textarea
有什么问题?
【问题讨论】:
我最初的想法是,当路由被解析时,DOM 无法滚动到。您是否尝试过编写一个小函数来滚动到mounted
上的 url 哈希中的元素
我也遇到了这个问题,最后编写了自己的函数让它跳转,因为我加载了异步内容,所以在加载异步数据后跳转需要准确,VueJS 尝试在之前跳转它已加载。
@Anuga 你在 scrollBehaviour 中写了你自己的函数吗?
不,我在需要滚动的组件中结合了 jQuery scrollTo 和一些自己的代码。在“挂载”之后,它会检查路径和哈希,并在页面加载完成时跳转。不是一个聪明的解决方案,但它完美无缺。
【参考方案1】:
使用left: 0, top: 0
而不是x: 0, y: 0
,它会起作用。
我认为这是 Vue 文档中的一个错误,因为如果您在控制台上登录 savedPosition
,您会看到 left: 0, top: 0
,而当您更改 x: 0, y: 0
时,一切都会正常运行。
【讨论】:
请提供您在其中找到此文件的文档的链接。我找到的帮助页面显示x:
和y:
是正确的。错误在其他地方。 router.vuejs.org/guide/advanced/scroll-behavior.html
实际上当我发现x:0,y:0
不能正常工作时,我在控制台上记录了 savedPosition 以查看 vue 默认格式是什么,它就是left: 0, top: 0
所以我这样更改了我的代码一切都很好。
好的,很好的发现。虽然我要说的是:单行不是你应该在 *** 中给出的答案。请添加到您的答案中,以帮助人们理解原因。添加你的轶事可能是一个开始,但假设官方文档是谎言有点牵强。
这值得一票。太感谢了。两年来他们的文件怎么出错了?
文档中的一切都很好,在 vue-router 3 的文档中表示为 x:0,y:0
,对于 vue-router 4 表示为 left: 0, top: 0
。你们都只是在这里使用不同版本的 vue-router。【参考方案2】:
我无法获得任何其他解决方案,这真的很令人沮丧。
最终为我工作的是以下内容:
const router = new Router(
mode: 'history',
routes: [...],
scrollBehavior()
document.getElementById('app').scrollIntoView();
)
我将我的 VueJs 应用程序安装到#app,因此我可以确定它存在并且可供选择。
【讨论】:
这确实有效,而 vue 官方文档中的代码示例却没有,至少对我来说是这样!【参考方案3】:这在 Vue 3 中对我有用:
const router = createRouter(
history: createWebHistory(process.env.BASE_URL),
routes,
scrollBehavior(to, from, SavedPosition)
if (to.hash)
const el = window.location.href.split("#")[1];
if (el.length)
document.getElementById(el).scrollIntoView( behavior: "smooth" );
else if (SavedPosition)
return SavedPosition;
else
document.getElementById("app").scrollIntoView( behavior: "smooth" );
,
);
【讨论】:
【参考方案4】:我将在这个问题上分享我的 2 美分,供像我这样正在寻找有效解决方案的人使用。拿起 Sweet Chilly Philly,回答这是唯一对我有用的东西,我正在添加相关代码以使 URL 哈希也能工作:
scrollBehavior: (to, from, savedPosition) =>
if (to.hash)
Vue.nextTick(() =>
document.getElementById(to.hash.substring(1)).scrollIntoView();
)
//Does not work but it's the vue way
return selector: to.hash
if (savedPosition)
//Did not test this but maybe it also does not work
return savedPosition
document.getElementById('app').scrollIntoView();
//Does not work but it's the vue way
return x: 0, y: 0
我不会详细介绍 Vue.nextTick(你可以阅读更多关于它的信息 here),但它会在下一次 DOM 更新之后运行代码,此时路由已经改变并且哈希引用的元素已经准备就绪,可以通过 document.getElementById() 访问。
【讨论】:
【参考方案5】:好的,所以我参加聚会有点晚了,但最近偶然发现了一个相当相似的问题。我无法让我的scrollBehavior
与锚一起工作。我终于找到了根本原因:我的<router-view>
被包裹在<transition>
中,这延迟了锚的渲染/安装,如下所示:
<Transition name="fade-transition" mode="out-in">
<RouterView />
</Transition>
发生了什么:
您点击带有锚点的重定向链接 路由器获取信息并更改 URL<router-view>
过渡开始。尚未安装新内容
滚动行为同时发生。未找到锚点,因此无法滚动
过渡结束,<router-view>
正确安装/渲染
没有过渡,scrollBehavior return selector: to.hash
工作正常,因为内容会立即挂载,并且锚点存在于页面中。
因为我不想删除过渡,所以我设计了一个变通方法,它会定期尝试获取锚元素,并在渲染/找到后滚动到它。它看起来像这样:
function wait(duration)
return new Promise((resolve) => setTimeout(resolve, duration));
async function tryScrollToAnchor(hash, timeout = 1000, delay = 100)
while (timeout > 0)
const el = document.querySelector(hash);
if (el)
el.scrollIntoView( behavior: "smooth" );
break;
await wait(delay);
timeout = timeout - delay;
scrollBehavior(to, from, savedPosition)
if (to.hash)
// Required because our <RouterView> is wrapped in a <Transition>
// So elements are mounted after a delay
tryScrollToAnchor(to.hash, 1000, 100);
else if (savedPosition)
return savedPosition;
else
return x: 0, y: 0 ;
【讨论】:
【参考方案6】:我有一个类似的问题,这是由我在网上找到的一些示例引起的。我的问题是该项目尚未呈现。我正在关闭转换的后离开事件,虽然它没有抛出任何错误,但它没有滚动到元素。我将其更改为过渡的 enter 事件,它现在可以工作了。
我知道这个问题没有提到过渡,所以在这种情况下,也许您可以尝试nextTick 而不是 setTimeout 来确保元素已呈现。
【讨论】:
【参考方案7】:正如@Xth 所指出的,围绕这个主题的很多困惑来自于 vue-router 版本 3 和 4 以不同方式处理 scrollBehaviour 参数这一事实。这是两种方式。
vue-router 4
scrollBehavior (to, from, savedPosition)
if (to.hash)
return
// x, y are replaced with left/top to define position, but when used with an element selector (el) will be used as offset
el: to.hash,
// offset has to be set as left and top at the top level
left: 0,
top: 64
官方文档V4:https://next.router.vuejs.org/guide/advanced/scroll-behavior.html
vue-router 3
scrollBehavior (to, from, savedPosition)
if (to.hash)
return
// x, y as top-level variables define position not offset
selector: to.hash,
// offset has to be set as an extra object
offset: x: 0, y: 64
官方文档V3:https://router.vuejs.org/guide/advanced/scroll-behavior.html
【讨论】:
【参考方案8】:以上建议都不适合我:
我发现它非常适合我的情况是这样的:
App.vue
<transition @before-enter="scrollTop" mode="out-in" appear>
<router-view></router-view>
</transition>
methods:
scrollTop()
document.getElementById('app').scrollIntoView();
,
【讨论】:
【参考方案9】:如果默认滚动查看不起作用,您可以通过以下方式获得相同的结果:
// src/rouer/index.js
[ //routes
path: '/name',
name: 'Name',
component: () => import('../component')
,
.
.
.
]
createRouter(
history: createWebHistory(process.env.BASE_URL),
routes,
scrollBehavior (to, from, SavedPosition)
if (to.hash)
const el = window.location.href.split('#')[1]
if (el.length)
document.getElementById(el).scrollIntoView( behavior: 'smooth' )
else if (SavedPosition)
return SavedPosition
else
document.getElementById('app').scrollIntoView( behavior: 'smooth' )
)
【讨论】:
【参考方案10】:你为什么要返回一个承诺? 文档只返回位置:https://router.vuejs.org/guide/advanced/scroll-behavior.html
所以应该改为:
scrollBehavior: function(to, from, savedPosition)
let position =
if (to.hash)
position =
selector : to.hash
;
else
position = x : 0 , y : 0
return position;
我还没有调试 to.hash
是否按您的预期工作,但这里的函数调用本身似乎不正确。
【讨论】:
【参考方案11】:对于遇到此问题的其他人,我发现删除主容器上的 overflow-x-hidden 可以解决问题。
【讨论】:
【参考方案12】:查看 vue-routers 对此功能的支持:
https://router.vuejs.org/guide/advanced/scroll-behavior.html
scrollBehavior (to, from, savedPosition)
if (to.hash)
return
selector: to.hash
// , offset: x: 0, y: 10
【讨论】:
感谢您的回答。我尝试了您的解决方案,但没有帮助。此外,在挂载块中,我尝试记录 document.getElementById(idToScrollTo) 并返回“null”。我勒个去 ? Mounted 意味着 DOM 必须存在。 另外,我发现滚动仅适用于 this.$refs.hash.$scrollIntoView() 。但我不能放置偏移或其他东西。我知道到底是什么以及为什么标准函数作为 scrollBehaviour 不起作用:( 我对此进行了更多思考并四处挖掘-您使用的是vue-router吗?如果是这样,他们确实支持此功能。 是的,正如您在问题的帖子中看到的那样,定义了 VueRouter 和 scrollBehaviour 函数。问题是滚动行为不起作用【参考方案13】:如果 jQuery 可用,这也可以工作:
scrollBehavior (to, from, savedPosition)
$('#selector-in-element-with-scroll').scrollTop(0)
【讨论】:
以上是关于滚动行为 VueJS 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章