滚动行为VueJS无法正常工作

时间:2019-02-05 13:45:07

标签: javascript vue.js vue-router

我试图通过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 组件上锚定<< strong> test ”

router.push()之后,我看到scrollBehavior被触发,组件从 tab1 切换到 tab3 ,并且URL也被更改(例如 http://localhost:8080/tab1 http://localhost:8080/tab3#test ),但窗口位置不在锚的位置,而只是在窗口顶部。

当然,我在tab3组件上有id =“ test”的文本区域

有什么问题吗?

11 个答案:

答案 0 :(得分:6)

使用 {left: 0, top: 0} 而不是 {x: 0, y: 0} 就可以了。

我认为这是 Vue 文档中的一个错误,因为如果您在控制台上登录 savedPosition,您将看到 {left: 0, top: 0},当您像这样更改 {x: 0, y: 0} 时,一切都会完美运行。< /p>

答案 1 :(得分:1)

这在 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" });
    }
  },
});

答案 2 :(得分:1)

好吧,我参加聚会有点晚了,但最近偶然发现了一个相当相似的问题。我无法使我的 scrollBehavior一起工作。我终于找到了根本原因:我的 <router-view> 被包裹在一个 <transition> 中,从而延迟了锚点的渲染/安装,如下所示:

<Transition name="fade-transition" mode="out-in">
  <RouterView />
</Transition>

发生的事情是:

  • 您点击带有锚点的重定向链接
  • 路由器获取信息并更改 URL
  • <router-view> 过渡开始。新内容尚未安装
  • scrollBehavior 同时发生。没有找到锚点,所以没有滚动
  • 过渡已结束,<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 };
  }
}

答案 3 :(得分:0)

查看此功能的vue-router支持:

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 }
    }
  }
}

答案 4 :(得分:0)

我无法获得与此工作相关的任何git解决方案,这实在令人沮丧。

最终为我工作的是以下内容:

const router = new Router({
    mode: 'history',
    routes: [...],
    scrollBehavior() {
        document.getElementById('app').scrollIntoView();
    }
})

我将VueJs应用程序安装到#app,因此可以确定它可以选择。

答案 5 :(得分:0)

如果jQuery可用,这也可以工作:

scrollBehavior (to, from, savedPosition) {    
  $('#selector-in-element-with-scroll').scrollTop(0)
}

答案 6 :(得分:0)

我有一个类似的问题,这是由于我在网上找到了一些例子而引起的。在我的情况下,问题在于该项目尚未渲染。我正在进行过渡的离开后事件,尽管它没有引发任何错误,但它没有滚动到该元素。我将其更改为过渡的enter事件,现在可以使用。

我知道问题没有提到过渡,因此在这种情况下,您可以尝试使用nextTick而不是setTimeout来确保元素已呈现。

答案 7 :(得分:0)

对于正在寻求有效解决方案的任何人,我将为此问题分享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()进行访问。

答案 8 :(得分:0)

以上建议都不适合我:

我发现并且非常适合我的情况是这样的:

App.vue

 <transition @before-enter="scrollTop" mode="out-in" appear>
   <router-view></router-view>
 </transition>

 methods: {
  scrollTop(){
    document.getElementById('app').scrollIntoView();
  },
}

答案 9 :(得分:0)

如果默认滚动查看不起作用,您可以通过以下方式获得相同的结果:

// 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 :(得分:0)

你为什么要返回一个承诺?
文档只返回位置: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 是否按您的预期工作,但这里的函数调用本身似乎不正确。