1
- import { getCurrentInstance , shallowReactive , effectScope , onUnmounted } from 'vue'
1
+ import {
2
+ getCurrentInstance ,
3
+ shallowReactive ,
4
+ effectScope ,
5
+ onUnmounted
6
+ } from 'vue'
2
7
3
8
export function useRouter ( ) {
4
9
const i = getCurrentInstance ( )
@@ -17,8 +22,8 @@ export function useRoute () {
17
22
18
23
const root = i . proxy . $root
19
24
if ( ! root . _$route ) {
20
- const route = effectScope ( true ) . run (
21
- ( ) => shallowReactive ( Object . assign ( { } , root . $router . currentRoute ) )
25
+ const route = effectScope ( true ) . run ( ( ) =>
26
+ shallowReactive ( Object . assign ( { } , root . $router . currentRoute ) )
22
27
)
23
28
root . _$route = route
24
29
@@ -39,33 +44,68 @@ export function onBeforeRouteUpdate (guard) {
39
44
throwNoCurrentInstance ( 'onBeforeRouteUpdate' )
40
45
}
41
46
47
+ return useFilteredGuard ( guard , isUpdateNavigation )
48
+ }
49
+
50
+ function useFilteredGuard ( guard , fn ) {
51
+ const i = getCurrentInstance ( )
42
52
const router = useRouter ( )
43
53
44
54
let target = i . proxy
45
55
// find the nearest routerview to know the depth
46
- while ( target && target . $vnode && target . $vnode . data && target . $vnode . data . routerViewDepth == null ) {
56
+ while (
57
+ target &&
58
+ target . $vnode &&
59
+ target . $vnode . data &&
60
+ target . $vnode . data . routerViewDepth == null
61
+ ) {
47
62
target = target . $parent
48
63
}
49
64
50
- const depth = target && target . $vnode && target . $vnode . data ? target . $vnode . data . routerViewDepth : null
65
+ const depth =
66
+ target && target . $vnode && target . $vnode . data
67
+ ? target . $vnode . data . routerViewDepth
68
+ : null
51
69
52
- console . log ( 'found depth' , depth )
70
+ if ( depth != null ) {
71
+ const removeGuard = router . beforeEach ( ( to , from , next ) => {
72
+ return fn ( to , from , depth ) ? guard ( to , from , next ) : next ( )
73
+ } )
53
74
54
- // TODO: allow multiple guards?
55
- i . proxy . $options . beforeRouteUpdate = guard
75
+ onUnmounted ( removeGuard )
76
+ return removeGuard
77
+ }
56
78
57
- const removeGuard = router . beforeEach ( ( to , from , next ) => {
58
- // TODO: check it's an update
59
- return guard ( to , from , next )
60
- } )
79
+ return noop
80
+ }
61
81
62
- onUnmounted ( removeGuard )
82
+ function isUpdateNavigation ( to , from , depth ) {
83
+ const toMatched = to . matched
84
+ const fromMatched = from . matched
85
+ return (
86
+ toMatched . length >= depth &&
87
+ toMatched
88
+ . slice ( 0 , depth + 1 )
89
+ . every ( ( record , i ) => record === fromMatched [ i ] )
90
+ )
91
+ }
63
92
64
- return removeGuard
93
+ function isLeaveNavigation ( to , from , depth ) {
94
+ const toMatched = to . matched
95
+ const fromMatched = from . matched
96
+ return toMatched . length < depth || toMatched [ depth ] !== fromMatched [ depth ]
65
97
}
66
98
67
- // TODO:
68
- // export function onBeforeRouteLeave () {}
99
+ const noop = ( ) => { }
100
+
101
+ export function onBeforeRouteLeave ( guard ) {
102
+ const i = getCurrentInstance ( )
103
+ if ( process . env . NODE_ENV !== 'production' && ! i ) {
104
+ throwNoCurrentInstance ( 'onBeforeRouteLeave' )
105
+ }
106
+
107
+ return useFilteredGuard ( guard , isLeaveNavigation )
108
+ }
69
109
70
110
function throwNoCurrentInstance ( method ) {
71
111
throw new Error (
0 commit comments