首页 > 解决方案 > 当我滚动 vue.js 中的组件时,如何动态更改 URL 中的哈希?

问题描述

我有一个包含许多组件的单页 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>

但是这不起作用,甚至没有执行的功能?

标签: vue.jsvue-router

解决方案


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

他们使用了一个名为VuePress的包,它有一个setActiveHash函数。

看起来他们debounce是滚动事件,然后使用 using 获取他们想要更改散列的所有元素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)
  }
}

推荐阅读