Skip to content

Commit 9861c55

Browse files
committed
feat: onBeforeRouteUpdatee onBeforeRouteLeave
1 parent 5bae10d commit 9861c55

File tree

2 files changed

+92
-24
lines changed

2 files changed

+92
-24
lines changed

examples/composables/app.js

+36-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,31 @@
1-
import Vue, { defineComponent, watch, ref, onUnmounted } from 'vue'
1+
import Vue, { defineComponent, watch, ref } from 'vue'
22
import VueRouter from 'vue-router'
33
import { useRoute, useRouter } from 'vue-router/composables'
4+
import { onBeforeRouteLeave, onBeforeRouteUpdate } from '../../src/composables'
45

56
Vue.use(VueRouter)
67

8+
const Foo = defineComponent({
9+
setup () {
10+
const route = useRoute()
11+
onBeforeRouteUpdate((to, from, next) => {
12+
console.log('Foo updating')
13+
next()
14+
})
15+
onBeforeRouteLeave((to, from, next) => {
16+
console.log('Foo leaving')
17+
next()
18+
})
19+
return { route }
20+
},
21+
template: `
22+
<div>
23+
<h3>Foo</h3>
24+
{{ route.fullPath }}
25+
</div>
26+
`
27+
})
28+
729
const Home = defineComponent({
830
setup () {
931
const route = useRoute()
@@ -12,19 +34,22 @@ const Home = defineComponent({
1234
// should be /
1335
const startRoute = route.fullPath
1436

15-
console.log('got to Home', startRoute)
37+
onBeforeRouteUpdate((to, from, next) => {
38+
console.log('Home updating')
39+
next()
40+
})
41+
42+
onBeforeRouteLeave((to, from, next) => {
43+
console.log('Home leaving')
44+
next()
45+
})
1646

1747
const watchCount = ref(0)
1848

1949
watch(() => route.query.n, () => {
20-
console.log('watched')
2150
watchCount.value++
2251
})
2352

24-
onUnmounted(() => {
25-
console.log('unmounted')
26-
})
27-
2853
function navigate () {
2954
router.push({ query: { n: 1 + (Number(route.query.n) || 0) }})
3055
}
@@ -37,8 +62,11 @@ const Home = defineComponent({
3762
<p id='watch-count'>{{ watchCount }}</p>
3863
<p id="fullpath">{{ route.fullPath }}</p>
3964
<button id="nav" @click="navigate">Navigate</button>
65+
<hr>
66+
<Foo />
4067
</div>
41-
`
68+
`,
69+
components: { Foo }
4270
})
4371

4472
const About = defineComponent({

src/composables/index.js

+56-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { getCurrentInstance, shallowReactive, effectScope, onUnmounted } from 'vue'
1+
import {
2+
getCurrentInstance,
3+
shallowReactive,
4+
effectScope,
5+
onUnmounted
6+
} from 'vue'
27

38
export function useRouter () {
49
const i = getCurrentInstance()
@@ -17,8 +22,8 @@ export function useRoute () {
1722

1823
const root = i.proxy.$root
1924
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))
2227
)
2328
root._$route = route
2429

@@ -39,33 +44,68 @@ export function onBeforeRouteUpdate (guard) {
3944
throwNoCurrentInstance('onBeforeRouteUpdate')
4045
}
4146

47+
return useFilteredGuard(guard, isUpdateNavigation)
48+
}
49+
50+
function useFilteredGuard (guard, fn) {
51+
const i = getCurrentInstance()
4252
const router = useRouter()
4353

4454
let target = i.proxy
4555
// 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+
) {
4762
target = target.$parent
4863
}
4964

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
5169

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+
})
5374

54-
// TODO: allow multiple guards?
55-
i.proxy.$options.beforeRouteUpdate = guard
75+
onUnmounted(removeGuard)
76+
return removeGuard
77+
}
5678

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+
}
6181

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+
}
6392

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]
6597
}
6698

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+
}
69109

70110
function throwNoCurrentInstance (method) {
71111
throw new Error(

0 commit comments

Comments
 (0)