当我滚动到vue.js中的组件时,如何动态更改URL中的散列?

2022-03-28 00:00:00 vue.js vue-router

我有一个带有多个组件的单页vue.js应用程序,现在我想在滚动这些组件时动态更改url中的散列。例如,如果您尝试在vue.js文档中滚动:

从以下位置滚动时,您会发现url正在更改:

https://v3.vuejs.org/guide/introduction.html#what-is-vue-js

至此:

https://v3.vuejs.org/guide/introduction.html#getting-started

以此类推。

我尝试在组件的第一个标记上创建@scroll="changeRoute",这会触发一个函数:

<script>
import { useRouter } from "vue-router";
export default {
  setup() {
    const router = useRouter();
    const changeRoute = () => {
      router.push({
        name: "Home",
        hash: "#landing-section",
      });
      console.log("route changes");
    };
    return {
      changeRoute,
    };
  },
};
</script>

b此操作不起作用,该函数甚至未执行?


解决方案

为了帮助您入门,因为您提供了VUE文档作为示例,所以您只能在他们的页面上查看它是如何工作的。

他们使用了名为VuePress的包,该包具有setActiveHash函数。

看起来像是他们debounce滚动事件,然后使用querySelectorAll获取他们要用来更改哈希的所有元素,然后确定这些元素是否处于活动状态,然后用活动的元素哈希替换当前的哈希。

/* global AHL_SIDEBAR_LINK_SELECTOR, AHL_HEADER_ANCHOR_SELECTOR */

import debounce from 'lodash.debounce'

export default {
  mounted () {
    window.addEventListener('scroll', this.onScroll)
  },

  methods: {
    onScroll: debounce(function () {
      this.setActiveHash()
    }, 300),

    setActiveHash () {
      const sidebarLinks = [].slice.call(document.querySelectorAll(AHL_SIDEBAR_LINK_SELECTOR))
      const anchors = [].slice.call(document.querySelectorAll(AHL_HEADER_ANCHOR_SELECTOR))
        .filter(anchor => sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash))

      const scrollTop = Math.max(
        window.pageYOffset,
        document.documentElement.scrollTop,
        document.body.scrollTop
      )

      const scrollHeight = Math.max(
        document.documentElement.scrollHeight,
        document.body.scrollHeight
      )

      const bottomY = window.innerHeight + scrollTop

      for (let i = 0; i < anchors.length; i++) {
        const anchor = anchors[i]
        const nextAnchor = anchors[i + 1]

        const isActive = i === 0 && scrollTop === 0
          || (scrollTop >= anchor.parentElement.offsetTop + 10
            && (!nextAnchor || scrollTop < nextAnchor.parentElement.offsetTop - 10))

        const routeHash = decodeURIComponent(this.$route.hash)
        if (isActive && routeHash !== decodeURIComponent(anchor.hash)) {
          const activeAnchor = anchor
          // check if anchor is at the bottom of the page to keep $route.hash consistent
          if (bottomY === scrollHeight) {
            for (let j = i + 1; j < anchors.length; j++) {
              if (routeHash === decodeURIComponent(anchors[j].hash)) {
                return
              }
            }
          }
          this.$vuepress.$set('disableScrollBehavior', true)
          this.$router.replace(decodeURIComponent(activeAnchor.hash), () => {
            // execute after scrollBehavior handler.
            this.$nextTick(() => {
              this.$vuepress.$set('disableScrollBehavior', false)
            })
          })
          return
        }
      }
    }
  },

  beforeDestroy () {
    window.removeEventListener('scroll', this.onScroll)
  }
}

相关文章