滚动行为 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/tab1http://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 &lt;router-view&gt; 过渡开始。尚未安装新内容 滚动行为同时发生。未找到锚点,因此无法滚动 过渡结束,&lt;router-view&gt; 正确安装/渲染

没有过渡,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 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

Vuejs jquery 数据表直接插件无法正常工作

嵌套滚动视图的滚动无法正常工作

在 div 内部时,jQuery 滚动无法正常工作

滚动后 UITableView 设计无法正常工作

滚动效果无法正常工作

搜索和过滤功能仍然无法正常工作(Vue JS)