如何使用Vue Router处理锚点(书签)?

时间:2017-07-19 21:07:07

标签: vue.js vuejs2 vue-router

我正在寻找一种智能方法来处理使用Vue Router的页内锚点。请考虑以下事项:

<router-link to="#app">Apply Now</router-link>
<!-- some HTML markup in between... -->
<div id="app">...</div>

“滚动到锚点”行为described in the docs可以正常工作,除了:

  • 当您点击锚点时,它会将您带到div id="app"。现在滚动离开div返回锚点并尝试再次点击它 - 这次你跳转到div。实际上,锚点将保留类router-link-active,并且URL仍将包含哈希值/#app;
  • 通过上述步骤,如果刷新页面(URL仍将包含哈希值)并单击锚点,则不会发生任何事情。

从UX角度来看,这是非常不幸的,因为潜在客户必须再次手动滚动才能到达应用程序部分。

我想知道Vue Router是否涵盖了这种情况。作为参考,这是我的路由器:

export default new VueRouter({
    routes,
    mode: 'history',
    scrollBehavior(to, from, savedPosition) {
        if (to.hash) {
            return { selector: to.hash }
        } else if (savedPosition) {
            return savedPosition;
        } else {
            return { x: 0, y: 0 }
        }
    }
})

5 个答案:

答案 0 :(得分:5)

我没有在资源中找到任何解决您问题的内容,但您可以在$route.hash的{​​{1}}组件中添加mounted来解决刷新问题

<router-view></router-view>

然后,要解决第二次点击问题,您可以使用<script> export default { name: 'app', mounted: function() { // From testing, without a brief timeout, it won't work. setTimeout(() => this.scrollFix(this.$route.hash), 1), }, methods: { scrollFix: function(hashbang) { location.href = hashbang; } } } </script> 修饰符并绑定到native。这是一个相当手动的过程,但会起作用。

<router-link></router-link>

路由器的<router-link to="#scroll" @click.native="scrollFix('#scroll')">Scroll</router-link> 方法可能还有一些功能,但还没有想到这一点。

答案 1 :(得分:1)

更可重复使用的可能解决方案IMO:

this.$router.push({ name: 'home' }, undefined, () => { location.href = this.$route.hash })

由于第3个参数是abort()函数,它可能会产生不必要的副作用..

如果要全局使用它,请在路由器中添加一个功能:

pushWithAnchor: function (routeName, toHash) {
    const fromHash = Router.history.current.hash
    fromHash !== toHash || !fromHash
    ? Router.push({ name: routeName, hash: toHash })
    : Router.push({ name: routeName, hash: fromHash }, undefined, () => { window.location.href = toHash })
  }

并在以下组件中使用它:

this.$router.options.pushWithAnchor('home', '#fee-calculator-section')

在模板中,您可以执行以下操作:

<a @click="this.$router.options.pushWithAnchor('home', '#fee-calculator-section')"></a>

可悲的是,你不能使用滚动偏移

答案 2 :(得分:1)

我使用了这个解决方案:

<router-link to="/about" @click.native="scrollFix('#team')" >The team</router-link>

而且:

methods: {
    scrollFix: function(hash) {
      setTimeout(() => $('html, body').animate({
      scrollTop: $(hash).offset().top
      }, 1000), 1)
    }
  }

答案 3 :(得分:0)

如果您已经在带有哈希的路线上,则可以将其设置为滚动到目标。

(还请注意,如果您已经在尝试访问的路由上,则不会调用路由器中的scrollBehavior()方法。)

export default {
  methods: {
    anchorHashCheck() {
      if (window.location.hash === this.$route.hash) {
        const el = document.getElementById(this.$route.hash.slice(1))
        if (el) {
          window.scrollTo(0, el.offsetTop)
        }
      }
    },
  },
  mounted() {
    this.anchorHashCheck()
  },
}

然后添加一个@click.native来监听<router-link>中锚点上的事件,

<router-link :to="{hash: '#some-link'}" @click.native="anchorHashCheck">
  Some link
</router-link>

答案 4 :(得分:0)

我知道您问起锚点了,您已经有了答案。但是,以下功能应同时适用于锚点和常规链接。它允许您滚动到与路线匹配的组件的第一个实例的位置。我写了它,看看是否可以绕过哈希来保留锚点样式的滚动。

scrollBehavior(to, from, savedPosition) {
if (to.matched) {
  const children = to.matched[1].parent.instances.default.$children;
  for (let i = 0; i < children.length; i++) {
    let child = children[i];
    if (child.$options._componentTag === to.matched[1].components.default.name) {
      return {
        x: child.$el.offsetLeft,
        y: child.$el.offsetTop
      };
    }
  }
}
return {
  x: 0,
  y: 0
};
}

我使用parent.instances的原因是因为to.matched[1].instances的值为空。尽管它可能会帮助其他人,但这并不是最优雅的解决方案。

注意:仅当您要滚动组件的第一个实例时,此方法才起作用。