알쏭달쏭 Nuxt.js 에서 앵커 링크 처리하기

Nuxt.js 는 여러모로 기본 Vue 하고도 다르고 SPA (Single Page Application) 에 알맞기 때문에 기존의 일반적인 페이지 처리와 다른 부분들이 있다.

특히 앵커에 대해서 처리가 많이 다른데…

예를 들어 일반적인 페이지 처리 환경인 그누보드 같은 게시글내에 특정 댓글로 바로 가야 한다면, 보통 URI 뒤에 #댓글아이디 식으로 앵커 링크를 넣고 호출하면 브라우저에서 자동으로 인식해서 스크롤된다.

하지만 Nuxt.js 환경에서는 앵커 스크롤 자체가 기본적으로 동작하지 않는다.

그래서 구글링 해보니 어느정도 도움이 될만한 것을 찾았다. 하지만 역시 정확이 원하는 데로 동작하지는 않았다. ㅜㅜ

도움글 : https://toor.co/blog/nuxtjs-smooth-scrolling-with-hash-links/

일단 작업중인 상황은 댓글링크를 클릭하면 바로 페이지가 바뀌는게 아니고 새 창이나 팝업창으로 띄워서 거기서 해당 댓글까지 스크롤이 되어야 한다.

위 글의 소스로는 처음 열릴때는 잘되지만… 동일한 URI의 또다른 댓글을 열면 스크롤이 되지 않는다.

이를 해결한 코드가 아래와 같다.

nuxt.config.js 파일에 아래와 같이 입력한다.

module.exports = {
  ...
  router: {
    // 기본 스크롤 행동을 아래와 같이 바꾼다. 댓글링크를 클릭시 게시글내의 댓글을 찾아갈 수 있도록 도와준다. (기본 브라우저 기능과 동일하게 동작하게 만든다.)
    scrollBehavior: async (to, from, savedPosition) => {
      /*
      // 만약 새창이나 새 팝업에 앵커 링크를 연다면 다시 다른 링크를 눌러 동일 URL의 앵커만 다른 경우 이 코드때문에 제대로 스크롤되지 않고 기존 스크롤을 그대로 유지한다. 이상하게 한번 더 앵커링크를 누르면 그때야 움직인다.
      if (savedPosition) {
        console.log('nuxt.config.js router: schrollBehavior(0): savedPosition', 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) {
        let el = await findEl(to.hash)
        if ('scrollBehavior' in document.documentElement.style) {
          return window.scrollTo({
            top: el.offsetTop,
            behavior: 'smooth'
          })
        } else {
          return window.scrollTo(0, el.offsetTop)
        }
      }

      return {
        x: 0,
        y: 0
      }
    } // scrollBehavior
  } // router
} // module.exports

위와 같이 savedPosition 처리를 제거하면 같은 URI의 다른 앵커 링크가 열려도 바로 스크롤이되어 원래 브라우저가 가진 기능과 거의 동일하게 할 수 있다.