티스토리 뷰

Dev

vue 에서 스크롤 위치 저장

hjhj97 2023. 3. 9. 01:23

SPA(Single Page Application)에서 이전 페이지의 스크롤 위치를 기억해두었다가 재방문 했을 때 그 자리에 위치해야 하는 경우가 있다. 이를 구현하기 위한 방법을 알아보자.

1. vue-router의 savedPosition 활용

vue-router의 createRouter()함수의 인자로 scrollBehavior함수를 넣을 수 있다.

const router = createRouter({
    history: createWebHistory(),
    routes,

    scrollBehavior(to, from, savedPosition) {
      // 기존 위치 존재하면 그 위치 반환
         if (savedPosition) {
             return savedPosition;
         }
     },
});

scrollBehavior 함수의 세 번재 인자로 savedPosition을 받을 수 있는데, 이 값을 return 해주게 되면 해당 스크롤 위치로 이동하게 된다. 다만 savedPosition 값은 사용자가 뒤로가기/앞으로가기 를 누를 때만 값이 활성화되고 vue-router를 활용하여 페이지 이동할 때는 값이 null값으로 반환되어서 위치를 저장할 수 없다. 만약 뒤로가기/앞으로가기 누를 때 뿐만 아니라 모든 경우에 대해서 스크롤 위치를 저장하기 위해서는 아래 2번 방법을 사용한다.

2. webStorage(sessionStorage) 활용

두 번째 방법은 브라우저 내의 webStorage를 활용하여 스크롤 위치를 동적으로 기억해 놓는 것이다. webStorage면 크게 localStorage와 sessionStorage가 있는데 차이는 브라우저를 닫았을 때 데이터가 날리느냐 마냐의 차이이다. 보통 웹사이트의 특정 기간동안 '로그인상태 유지' 기능이 활성화한다면 브라우저가 꺼져도 유지되야 하므로 localStorage에 저장하는게 적합하다. 스크롤 위치 정보의 경우 브라우저를 껐다가 다시 실행했을 경우에는 초기화 시키는게 적합하므로 sessionStorage에 저장하기로 했다.

  1. 페이지를 이동할 때마다 현재 페이지의 스크롤 위치를 저장해두어야 한다.
    따라서 vue-router의 beforeEach()함수 내부에 현재 페이지의 위치인 window.scrollY 값을 sessionStorage에 key-value 형태의 map(아래 코드에서는 scrollInfo)으로 저장한다.이때 webStorage에는 string형태의 데이터만 저장할 수 있으므로 저장할 때는 JSON.stringify()로, 값을 꺼낼 때는 JSON.parse()함수를 거쳐야 한다.

    router.beforeEach((to, from) => {
        const prevInfo = JSON.parse(window.sessionStorage.getItem('scrollInfo'));
    
        const key = from.name;
        if (key) {
            const scrollObj = { [key]: window.scrollY };
            window.sessionStorage.setItem('scrollInfo', JSON.stringify({ ...prevInfo, ...scrollObj }));
        }
    });
  2. 특정 페이지에 진입하면 scrollInfo에서 이전에 저장되어 있는 스크롤 위치가 있는지 확인한 후, 있다면 그 위치로 이동시킨다.

   const router = createRouter({
    history: createWebHistory(),
    routes,
    scrollBehavior(to) {
           const prevInfo = JSON.parse(window.sessionStorage.getItem('scrollInfo'));
           if (prevInfo[to.name] >= 0) {
               return window.scrollTo(0, prevInfo[to.name]);
           }
       },
   });
댓글