Article Content Selector with Scroll-To

I used the code from Nuxt.js Smooth Scrolling with Hash Links and added highlighting by adding/removing a class.

  // in nuxt.config.js
  router: {
    scrollBehavior: async (to, from, savedPosition) => {
      if (savedPosition) {
        return savedPosition
      }

      const findEl = async (hash, x) => {
        return (
          document.querySelector(hash) ||
          new Promise((resolve, reject) => {
            if (x > 50) {
              return resolve()
            }
            setTimeout(() => {
              resolve(findEl(hash, ++x || 1))
            }, 100)
          })
        )
      }

      if (to.hash) {
        // scroll to hash in url

        const el = await findEl(to.hash)
        if ('scrollBehavior' in document.documentElement.style) {
          // remove any existing highlight and add highlight
          const highlightClass = 'highlight-hash'
          const hasClass = document.getElementsByClassName(highlightClass)
          Array.from(hasClass).forEach((el) =>
            el.classList.remove(highlightClass)
          )
          el.classList.add(highlightClass)

          return window.scrollTo({ top: el.offsetTop, behavior: 'smooth' })
        } else {
          return window.scrollTo(0, el.offsetTop)
        }
      }

      return { x: 0, y: 0 }
    }
  }
<ArticleContentSelector
  :article="article"
  @change="$router.push(...arguments)"
/>

========== REWORK BELOW

The Content selector uses the Vuetify v-select component. When the selector is changed, we push only the hash. The router code above handles scrolling and highlighting.

      <v-select
        v-model="contentSelected"
        class="content-selector"
        :items="contentItems"
        label="Contents"
        outlined
        @change="$router.push({ hash: contentSelected })"
      ></v-select>

Inside of the mounted() method

    // on page load, set the Contents selector to the correct element
    const noHashHash = this.$route.hash.replace('#', '')
    if (noHashHash) {
      const id = this.contentItems.findIndex(
        (item) => item.value === noHashHash
      )
      if (id > -1) {
        this.selectedItem = id
        this.contentSelected = this.contentItems[id].value
      }
    }
Background image by Joel Chavarría on Unsplash