返回 slidev
useViewTransition.ts
根目录 / packages / client / composables / useViewTransition.ts
1 import { ref } from 'vue'
2 import { useRouter } from 'vue-router'
3 import { configs } from '../env'
4 import { getSlide } from '../logic/slides'
5
6 export function useViewTransition() {
7 const router = useRouter()
8 const isViewTransition = ref(false)
9
10 let viewTransitionFinish: undefined | (() => void)
11 let viewTransitionAbort: undefined | (() => void)
12
13 const supportViewTransition = typeof document !== 'undefined' && 'startViewTransition' in document
14
15 router.beforeResolve((to, from) => {
16 const fromMeta = getSlide(from.params.no as string)?.meta
17 const toMeta = getSlide(to.params.no as string)?.meta
18 const fromNo = fromMeta?.slide?.no
19 const toNo = toMeta?.slide?.no
20 const transitionType = fromNo != null && toNo != null && fromNo !== toNo
21 && ((fromNo < toNo ? fromMeta?.transition : toMeta?.transition) ?? configs.transition)
22 if (transitionType !== 'view-transition') {
23 isViewTransition.value = false
24 return
25 }
26
27 if (!supportViewTransition) {
28 isViewTransition.value = false
29 console.warn('View transition is not supported in your browser, fallback to normal transition.')
30 return
31 }
32
33 isViewTransition.value = true
34 const promise = new Promise<void>((resolve, reject) => {
35 viewTransitionFinish = resolve
36 viewTransitionAbort = reject
37 })
38
39 let changeRoute: () => void
40 const ready = new Promise<void>(resolve => (changeRoute = resolve))
41
42 // Wait for `TransitionGroup` to become normal `div`
43 setTimeout(() => {
44 document.startViewTransition(() => {
45 changeRoute()
46 return promise
47 })
48 }, 50)
49
50 return ready
51 })
52
53 if (supportViewTransition) {
54 router.afterEach(() => {
55 viewTransitionFinish?.()
56 viewTransitionAbort?.()
57 })
58 }
59
60 return isViewTransition
61 }
62
62 lines TYPESCRIPT