스크롤 동작
클라이언트 사이드 라우팅을 사용할 때는 새 라우트로 이동하면 맨 위로 스크롤하거나, 실제 페이지 새로고침처럼 히스토리 항목의 스크롤 위치를 유지하고 싶을 수 있습니다. Vue Router는 이를 가능하게 할 뿐 아니라, 라우트 내비게이션 시 스크롤 동작을 완전히 사용자 정의할 수 있게 해줍니다.
참고: 이 기능은 브라우저가 history.pushState를 지원할 때만 동작합니다.
라우터 인스턴스를 만들 때 scrollBehavior 함수를 제공할 수 있습니다:
const router = createRouter({
history: createWebHashHistory(),
routes: [...],
scrollBehavior (to, from, savedPosition) {
// 원하는 위치를 반환합니다
}
})scrollBehavior 함수는 내비게이션 가드처럼 to와 from 라우트 객체를 받습니다. 세 번째 인자인 savedPosition은 이것이 popstate 내비게이션(브라우저 뒤로/앞으로 버튼으로 트리거됨)일 때만 사용할 수 있습니다.
이 함수는 ScrollToOptions 위치 객체를 반환할 수 있습니다:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
// 항상 맨 위로 스크롤합니다
return { top: 0 }
},
})el을 통해 CSS 선택자나 DOM 요소를 전달할 수도 있습니다. 이 경우 top과 left는 해당 요소에 대한 상대 오프셋으로 처리됩니다.
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
// 항상 #main 요소의 10px 위로 스크롤합니다
return {
// 다음과 같이 쓸 수도 있습니다
// el: document.getElementById('main'),
el: '#main',
// 요소 위로 10px
top: 10,
}
},
})falsy 값이나 빈 객체를 반환하면 스크롤이 일어나지 않습니다.
savedPosition을 반환하면 뒤로/앞으로 버튼으로 이동할 때 네이티브와 비슷한 동작을 하게 됩니다:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
},
})"앵커로 스크롤" 동작을 흉내 내고 싶다면:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
}
}
},
})브라우저가 scroll behavior를 지원한다면 부드럽게 만들 수 있습니다:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
behavior: 'smooth',
}
}
},
})스크롤 지연하기
때로는 페이지에서 스크롤하기 전에 잠시 기다려야 합니다. 예를 들어 transition을 다룰 때는 transition이 끝난 뒤 스크롤하고 싶을 수 있습니다. 이를 위해 원하는 위치 descriptor를 반환하는 Promise를 반환할 수 있습니다. 다음은 500ms 기다린 뒤 스크롤하는 예제입니다:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ left: 0, top: 0 })
}, 500)
})
},
})페이지 수준 transition 컴포넌트의 이벤트와 연결해 스크롤 동작이 페이지 전환과 잘 어우러지도록 만들 수 있습니다. 하지만 사용 사례의 다양성과 복잡성 때문에, 여기서는 특정 userland 구현을 가능하게 하는 이 기본 수단만 제공합니다.
고급 오프셋
페이지에 고정 네비게이션 바 같은 요소가 있다면, 대상 요소가 다른 콘텐츠 뒤에 가려지지 않도록 오프셋이 필요할 수 있습니다. 정적인 오프셋 값을 사용하는 방식은 항상 잘 동작하지는 않습니다. scroll-margin, scroll-padding을 사용하거나 ::before, ::after 가상 요소를 사용하는 CSS 기반 해결책을 시도할 수 있지만, 이런 접근은 예상치 못한 동작을 일으킬 수 있습니다.
이런 경우에는 오프셋을 수동으로 계산하는 편이 더 좋습니다. 간단한 방법은 CSS와 JavaScript의 getComputedStyle()을 결합하는 것입니다. 이렇게 하면 각 요소가 자신의 오프셋을 동적으로 정의할 수 있습니다. 예:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
const mainElement = document.querySelector('#main')
if (mainElement) {
const marginTop = parseFloat(
getComputedStyle(mainElement).scrollMarginTop
)
return {
el: mainElement,
top: marginTop,
}
} else {
return { top: 0 }
}
},
})