kdu-router 3.5.4 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +11 -11
- package/dist/composables.js +253 -0
- package/dist/composables.mjs +244 -0
- package/dist/kdu-router.common.js +2668 -2665
- package/dist/kdu-router.esm.browser.js +2677 -2671
- package/dist/kdu-router.esm.browser.min.js +5 -5
- package/dist/kdu-router.esm.js +2672 -2666
- package/dist/kdu-router.js +2675 -2672
- package/dist/kdu-router.min.js +5 -5
- package/ketur/attributes.json +38 -38
- package/ketur/tags.json +20 -20
- package/package.json +115 -90
- package/src/components/link.js +224 -224
- package/src/components/view.js +155 -155
- package/src/composables/globals.js +34 -0
- package/src/composables/guards.js +68 -0
- package/src/composables/index.js +3 -0
- package/src/composables/useLink.js +113 -0
- package/src/composables/utils.js +11 -0
- package/src/create-matcher.js +226 -226
- package/src/create-route-map.js +220 -220
- package/src/entries/cjs.js +3 -0
- package/src/entries/esm.js +12 -0
- package/src/history/abstract.js +72 -72
- package/src/history/base.js +379 -379
- package/src/history/hash.js +152 -152
- package/src/history/html5.js +99 -99
- package/src/index.js +3 -293
- package/src/install.js +52 -52
- package/src/router.js +293 -0
- package/src/util/async.js +18 -18
- package/src/util/dom.js +3 -3
- package/src/util/errors.js +86 -86
- package/src/util/location.js +69 -69
- package/src/util/misc.js +6 -6
- package/src/util/params.js +37 -37
- package/src/util/path.js +74 -74
- package/src/util/push-state.js +46 -46
- package/src/util/query.js +113 -113
- package/src/util/resolve-components.js +109 -109
- package/src/util/route.js +151 -151
- package/src/util/scroll.js +175 -175
- package/src/util/state-key.js +22 -22
- package/src/util/warn.js +14 -14
- package/types/composables.d.ts +53 -0
- package/types/index.d.ts +25 -21
- package/types/kdu.d.ts +22 -22
- package/types/router.d.ts +564 -211
package/src/components/view.js
CHANGED
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
import { warn } from '../util/warn'
|
|
2
|
-
import { extend } from '../util/misc'
|
|
3
|
-
import { handleRouteEntered } from '../util/route'
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
name: 'RouterView',
|
|
7
|
-
functional: true,
|
|
8
|
-
props: {
|
|
9
|
-
name: {
|
|
10
|
-
type: String,
|
|
11
|
-
default: 'default'
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
render (_, { props, children, parent, data }) {
|
|
15
|
-
// used by devtools to display a router-view badge
|
|
16
|
-
data.routerView = true
|
|
17
|
-
|
|
18
|
-
// directly use parent context's createElement() function
|
|
19
|
-
// so that components rendered by router-view can resolve named slots
|
|
20
|
-
const h = parent.$createElement
|
|
21
|
-
const name = props.name
|
|
22
|
-
const route = parent.$route
|
|
23
|
-
const cache = parent._routerViewCache || (parent._routerViewCache = {})
|
|
24
|
-
|
|
25
|
-
// determine current view depth, also check to see if the tree
|
|
26
|
-
// has been toggled inactive but kept-alive.
|
|
27
|
-
let depth = 0
|
|
28
|
-
let inactive = false
|
|
29
|
-
while (parent && parent._routerRoot !== parent) {
|
|
30
|
-
const knodeData = parent.$knode ? parent.$knode.data : {}
|
|
31
|
-
if (knodeData.routerView) {
|
|
32
|
-
depth++
|
|
33
|
-
}
|
|
34
|
-
if (knodeData.keepAlive && parent._directInactive && parent._inactive) {
|
|
35
|
-
inactive = true
|
|
36
|
-
}
|
|
37
|
-
parent = parent.$parent
|
|
38
|
-
}
|
|
39
|
-
data.routerViewDepth = depth
|
|
40
|
-
|
|
41
|
-
// render previous view if the tree is inactive and kept-alive
|
|
42
|
-
if (inactive) {
|
|
43
|
-
const cachedData = cache[name]
|
|
44
|
-
const cachedComponent = cachedData && cachedData.component
|
|
45
|
-
if (cachedComponent) {
|
|
46
|
-
// #2301
|
|
47
|
-
// pass props
|
|
48
|
-
if (cachedData.configProps) {
|
|
49
|
-
fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps)
|
|
50
|
-
}
|
|
51
|
-
return h(cachedComponent, data, children)
|
|
52
|
-
} else {
|
|
53
|
-
// render previous empty view
|
|
54
|
-
return h()
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const matched = route.matched[depth]
|
|
59
|
-
const component = matched && matched.components[name]
|
|
60
|
-
|
|
61
|
-
// render empty node if no matched route or no config component
|
|
62
|
-
if (!matched || !component) {
|
|
63
|
-
cache[name] = null
|
|
64
|
-
return h()
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// cache component
|
|
68
|
-
cache[name] = { component }
|
|
69
|
-
|
|
70
|
-
// attach instance registration hook
|
|
71
|
-
// this will be called in the instance's injected lifecycle hooks
|
|
72
|
-
data.registerRouteInstance = (vm, val) => {
|
|
73
|
-
// val could be undefined for unregistration
|
|
74
|
-
const current = matched.instances[name]
|
|
75
|
-
if (
|
|
76
|
-
(val && current !== vm) ||
|
|
77
|
-
(!val && current === vm)
|
|
78
|
-
) {
|
|
79
|
-
matched.instances[name] = val
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// also register instance in prepatch hook
|
|
84
|
-
// in case the same component instance is reused across different routes
|
|
85
|
-
;(data.hook || (data.hook = {})).prepatch = (_, knode) => {
|
|
86
|
-
matched.instances[name] = knode.componentInstance
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// register instance in init hook
|
|
90
|
-
// in case kept-alive component be actived when routes changed
|
|
91
|
-
data.hook.init = (knode) => {
|
|
92
|
-
if (knode.data.keepAlive &&
|
|
93
|
-
knode.componentInstance &&
|
|
94
|
-
knode.componentInstance !== matched.instances[name]
|
|
95
|
-
) {
|
|
96
|
-
matched.instances[name] = knode.componentInstance
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// if the route transition has already been confirmed then we weren't
|
|
100
|
-
// able to call the cbs during confirmation as the component was not
|
|
101
|
-
// registered yet, so we call it here.
|
|
102
|
-
handleRouteEntered(route)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const configProps = matched.props && matched.props[name]
|
|
106
|
-
// save route and configProps in cache
|
|
107
|
-
if (configProps) {
|
|
108
|
-
extend(cache[name], {
|
|
109
|
-
route,
|
|
110
|
-
configProps
|
|
111
|
-
})
|
|
112
|
-
fillPropsinData(component, data, route, configProps)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return h(component, data, children)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function fillPropsinData (component, data, route, configProps) {
|
|
120
|
-
// resolve props
|
|
121
|
-
let propsToPass = data.props = resolveProps(route, configProps)
|
|
122
|
-
if (propsToPass) {
|
|
123
|
-
// clone to prevent mutation
|
|
124
|
-
propsToPass = data.props = extend({}, propsToPass)
|
|
125
|
-
// pass non-declared props as attrs
|
|
126
|
-
const attrs = data.attrs = data.attrs || {}
|
|
127
|
-
for (const key in propsToPass) {
|
|
128
|
-
if (!component.props || !(key in component.props)) {
|
|
129
|
-
attrs[key] = propsToPass[key]
|
|
130
|
-
delete propsToPass[key]
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function resolveProps (route, config) {
|
|
137
|
-
switch (typeof config) {
|
|
138
|
-
case 'undefined':
|
|
139
|
-
return
|
|
140
|
-
case 'object':
|
|
141
|
-
return config
|
|
142
|
-
case 'function':
|
|
143
|
-
return config(route)
|
|
144
|
-
case 'boolean':
|
|
145
|
-
return config ? route.params : undefined
|
|
146
|
-
default:
|
|
147
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
148
|
-
warn(
|
|
149
|
-
false,
|
|
150
|
-
`props in "${route.path}" is a ${typeof config}, ` +
|
|
151
|
-
`expecting an object, function or boolean.`
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
1
|
+
import { warn } from '../util/warn'
|
|
2
|
+
import { extend } from '../util/misc'
|
|
3
|
+
import { handleRouteEntered } from '../util/route'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
name: 'RouterView',
|
|
7
|
+
functional: true,
|
|
8
|
+
props: {
|
|
9
|
+
name: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: 'default'
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
render (_, { props, children, parent, data }) {
|
|
15
|
+
// used by devtools to display a router-view badge
|
|
16
|
+
data.routerView = true
|
|
17
|
+
|
|
18
|
+
// directly use parent context's createElement() function
|
|
19
|
+
// so that components rendered by router-view can resolve named slots
|
|
20
|
+
const h = parent.$createElement
|
|
21
|
+
const name = props.name
|
|
22
|
+
const route = parent.$route
|
|
23
|
+
const cache = parent._routerViewCache || (parent._routerViewCache = {})
|
|
24
|
+
|
|
25
|
+
// determine current view depth, also check to see if the tree
|
|
26
|
+
// has been toggled inactive but kept-alive.
|
|
27
|
+
let depth = 0
|
|
28
|
+
let inactive = false
|
|
29
|
+
while (parent && parent._routerRoot !== parent) {
|
|
30
|
+
const knodeData = parent.$knode ? parent.$knode.data : {}
|
|
31
|
+
if (knodeData.routerView) {
|
|
32
|
+
depth++
|
|
33
|
+
}
|
|
34
|
+
if (knodeData.keepAlive && parent._directInactive && parent._inactive) {
|
|
35
|
+
inactive = true
|
|
36
|
+
}
|
|
37
|
+
parent = parent.$parent
|
|
38
|
+
}
|
|
39
|
+
data.routerViewDepth = depth
|
|
40
|
+
|
|
41
|
+
// render previous view if the tree is inactive and kept-alive
|
|
42
|
+
if (inactive) {
|
|
43
|
+
const cachedData = cache[name]
|
|
44
|
+
const cachedComponent = cachedData && cachedData.component
|
|
45
|
+
if (cachedComponent) {
|
|
46
|
+
// #2301
|
|
47
|
+
// pass props
|
|
48
|
+
if (cachedData.configProps) {
|
|
49
|
+
fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps)
|
|
50
|
+
}
|
|
51
|
+
return h(cachedComponent, data, children)
|
|
52
|
+
} else {
|
|
53
|
+
// render previous empty view
|
|
54
|
+
return h()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const matched = route.matched[depth]
|
|
59
|
+
const component = matched && matched.components[name]
|
|
60
|
+
|
|
61
|
+
// render empty node if no matched route or no config component
|
|
62
|
+
if (!matched || !component) {
|
|
63
|
+
cache[name] = null
|
|
64
|
+
return h()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// cache component
|
|
68
|
+
cache[name] = { component }
|
|
69
|
+
|
|
70
|
+
// attach instance registration hook
|
|
71
|
+
// this will be called in the instance's injected lifecycle hooks
|
|
72
|
+
data.registerRouteInstance = (vm, val) => {
|
|
73
|
+
// val could be undefined for unregistration
|
|
74
|
+
const current = matched.instances[name]
|
|
75
|
+
if (
|
|
76
|
+
(val && current !== vm) ||
|
|
77
|
+
(!val && current === vm)
|
|
78
|
+
) {
|
|
79
|
+
matched.instances[name] = val
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// also register instance in prepatch hook
|
|
84
|
+
// in case the same component instance is reused across different routes
|
|
85
|
+
;(data.hook || (data.hook = {})).prepatch = (_, knode) => {
|
|
86
|
+
matched.instances[name] = knode.componentInstance
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// register instance in init hook
|
|
90
|
+
// in case kept-alive component be actived when routes changed
|
|
91
|
+
data.hook.init = (knode) => {
|
|
92
|
+
if (knode.data.keepAlive &&
|
|
93
|
+
knode.componentInstance &&
|
|
94
|
+
knode.componentInstance !== matched.instances[name]
|
|
95
|
+
) {
|
|
96
|
+
matched.instances[name] = knode.componentInstance
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// if the route transition has already been confirmed then we weren't
|
|
100
|
+
// able to call the cbs during confirmation as the component was not
|
|
101
|
+
// registered yet, so we call it here.
|
|
102
|
+
handleRouteEntered(route)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const configProps = matched.props && matched.props[name]
|
|
106
|
+
// save route and configProps in cache
|
|
107
|
+
if (configProps) {
|
|
108
|
+
extend(cache[name], {
|
|
109
|
+
route,
|
|
110
|
+
configProps
|
|
111
|
+
})
|
|
112
|
+
fillPropsinData(component, data, route, configProps)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return h(component, data, children)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function fillPropsinData (component, data, route, configProps) {
|
|
120
|
+
// resolve props
|
|
121
|
+
let propsToPass = data.props = resolveProps(route, configProps)
|
|
122
|
+
if (propsToPass) {
|
|
123
|
+
// clone to prevent mutation
|
|
124
|
+
propsToPass = data.props = extend({}, propsToPass)
|
|
125
|
+
// pass non-declared props as attrs
|
|
126
|
+
const attrs = data.attrs = data.attrs || {}
|
|
127
|
+
for (const key in propsToPass) {
|
|
128
|
+
if (!component.props || !(key in component.props)) {
|
|
129
|
+
attrs[key] = propsToPass[key]
|
|
130
|
+
delete propsToPass[key]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resolveProps (route, config) {
|
|
137
|
+
switch (typeof config) {
|
|
138
|
+
case 'undefined':
|
|
139
|
+
return
|
|
140
|
+
case 'object':
|
|
141
|
+
return config
|
|
142
|
+
case 'function':
|
|
143
|
+
return config(route)
|
|
144
|
+
case 'boolean':
|
|
145
|
+
return config ? route.params : undefined
|
|
146
|
+
default:
|
|
147
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
148
|
+
warn(
|
|
149
|
+
false,
|
|
150
|
+
`props in "${route.path}" is a ${typeof config}, ` +
|
|
151
|
+
`expecting an object, function or boolean.`
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCurrentInstance,
|
|
3
|
+
shallowReactive,
|
|
4
|
+
effectScope
|
|
5
|
+
} from 'kdu'
|
|
6
|
+
import { throwNoCurrentInstance } from './utils'
|
|
7
|
+
|
|
8
|
+
export function useRouter () {
|
|
9
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
10
|
+
throwNoCurrentInstance('useRouter')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return getCurrentInstance().proxy.$root.$router
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useRoute () {
|
|
17
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
18
|
+
throwNoCurrentInstance('useRoute')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const root = getCurrentInstance().proxy.$root
|
|
22
|
+
if (!root._$route) {
|
|
23
|
+
const route = effectScope(true).run(() =>
|
|
24
|
+
shallowReactive(Object.assign({}, root.$router.currentRoute))
|
|
25
|
+
)
|
|
26
|
+
root._$route = route
|
|
27
|
+
|
|
28
|
+
root.$router.afterEach(to => {
|
|
29
|
+
Object.assign(route, to)
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return root._$route
|
|
34
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getCurrentInstance, onUnmounted } from 'kdu'
|
|
2
|
+
import { throwNoCurrentInstance } from './utils'
|
|
3
|
+
import { useRouter } from './globals'
|
|
4
|
+
|
|
5
|
+
export function onBeforeRouteUpdate (guard) {
|
|
6
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7
|
+
throwNoCurrentInstance('onBeforeRouteUpdate')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return useFilteredGuard(guard, isUpdateNavigation)
|
|
11
|
+
}
|
|
12
|
+
function isUpdateNavigation (to, from, depth) {
|
|
13
|
+
const toMatched = to.matched
|
|
14
|
+
const fromMatched = from.matched
|
|
15
|
+
return (
|
|
16
|
+
toMatched.length >= depth &&
|
|
17
|
+
toMatched
|
|
18
|
+
.slice(0, depth + 1)
|
|
19
|
+
.every((record, i) => record === fromMatched[i])
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isLeaveNavigation (to, from, depth) {
|
|
24
|
+
const toMatched = to.matched
|
|
25
|
+
const fromMatched = from.matched
|
|
26
|
+
return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function onBeforeRouteLeave (guard) {
|
|
30
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
31
|
+
throwNoCurrentInstance('onBeforeRouteLeave')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return useFilteredGuard(guard, isLeaveNavigation)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const noop = () => {}
|
|
38
|
+
function useFilteredGuard (guard, fn) {
|
|
39
|
+
const instance = getCurrentInstance()
|
|
40
|
+
const router = useRouter()
|
|
41
|
+
|
|
42
|
+
let target = instance.proxy
|
|
43
|
+
// find the nearest RouterView to know the depth
|
|
44
|
+
while (
|
|
45
|
+
target &&
|
|
46
|
+
target.$knode &&
|
|
47
|
+
target.$knode.data &&
|
|
48
|
+
target.$knode.data.routerViewDepth == null
|
|
49
|
+
) {
|
|
50
|
+
target = target.$parent
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const depth =
|
|
54
|
+
target && target.$knode && target.$knode.data
|
|
55
|
+
? target.$knode.data.routerViewDepth
|
|
56
|
+
: null
|
|
57
|
+
|
|
58
|
+
if (depth != null) {
|
|
59
|
+
const removeGuard = router.beforeEach((to, from, next) => {
|
|
60
|
+
return fn(to, from, depth) ? guard(to, from, next) : next()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
onUnmounted(removeGuard)
|
|
64
|
+
return removeGuard
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return noop
|
|
68
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { computed, unref } from 'kdu'
|
|
2
|
+
import { guardEvent } from '../components/link'
|
|
3
|
+
import { throwNoCurrentInstance } from './utils'
|
|
4
|
+
import { useRouter, useRoute } from './globals'
|
|
5
|
+
|
|
6
|
+
function includesParams (outer, inner) {
|
|
7
|
+
for (const key in inner) {
|
|
8
|
+
const innerValue = inner[key]
|
|
9
|
+
const outerValue = outer[key]
|
|
10
|
+
if (typeof innerValue === 'string') {
|
|
11
|
+
if (innerValue !== outerValue) return false
|
|
12
|
+
} else {
|
|
13
|
+
if (
|
|
14
|
+
!Array.isArray(outerValue) ||
|
|
15
|
+
outerValue.length !== innerValue.length ||
|
|
16
|
+
innerValue.some((value, i) => value !== outerValue[i])
|
|
17
|
+
) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// helpers from kdu router 4
|
|
27
|
+
|
|
28
|
+
function isSameRouteLocationParamsValue (a, b) {
|
|
29
|
+
return Array.isArray(a)
|
|
30
|
+
? isEquivalentArray(a, b)
|
|
31
|
+
: Array.isArray(b)
|
|
32
|
+
? isEquivalentArray(b, a)
|
|
33
|
+
: a === b
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isEquivalentArray (a, b) {
|
|
37
|
+
return Array.isArray(b)
|
|
38
|
+
? a.length === b.length && a.every((value, i) => value === b[i])
|
|
39
|
+
: a.length === 1 && a[0] === b
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isSameRouteLocationParams (a, b) {
|
|
43
|
+
if (Object.keys(a).length !== Object.keys(b).length) return false
|
|
44
|
+
|
|
45
|
+
for (const key in a) {
|
|
46
|
+
if (!isSameRouteLocationParamsValue(a[key], b[key])) return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useLink (props) {
|
|
53
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
54
|
+
throwNoCurrentInstance('useLink')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const router = useRouter()
|
|
58
|
+
const currentRoute = useRoute()
|
|
59
|
+
|
|
60
|
+
const resolvedRoute = computed(() => router.resolve(unref(props.to), currentRoute))
|
|
61
|
+
|
|
62
|
+
const activeRecordIndex = computed(() => {
|
|
63
|
+
const route = resolvedRoute.value.route
|
|
64
|
+
const { matched } = route
|
|
65
|
+
const { length } = matched
|
|
66
|
+
const routeMatched = matched[length - 1]
|
|
67
|
+
const currentMatched = currentRoute.matched
|
|
68
|
+
if (!routeMatched || !currentMatched.length) return -1
|
|
69
|
+
const index = currentMatched.indexOf(routeMatched)
|
|
70
|
+
if (index > -1) return index
|
|
71
|
+
// possible parent record
|
|
72
|
+
const parentRecord = currentMatched[currentMatched.length - 2]
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
// we are dealing with nested routes
|
|
76
|
+
length > 1 &&
|
|
77
|
+
// if the parent and matched route have the same path, this link is
|
|
78
|
+
// referring to the empty child. Or we currently are on a different
|
|
79
|
+
// child of the same parent
|
|
80
|
+
parentRecord && parentRecord === routeMatched.parent
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const isActive = computed(
|
|
85
|
+
() =>
|
|
86
|
+
activeRecordIndex.value > -1 &&
|
|
87
|
+
includesParams(currentRoute.params, resolvedRoute.value.route.params)
|
|
88
|
+
)
|
|
89
|
+
const isExactActive = computed(
|
|
90
|
+
() =>
|
|
91
|
+
activeRecordIndex.value > -1 &&
|
|
92
|
+
activeRecordIndex.value === currentRoute.matched.length - 1 &&
|
|
93
|
+
isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const navigate = e => {
|
|
97
|
+
const href = resolvedRoute.value.route
|
|
98
|
+
if (guardEvent(e)) {
|
|
99
|
+
return props.replace
|
|
100
|
+
? router.replace(href)
|
|
101
|
+
: router.push(href)
|
|
102
|
+
}
|
|
103
|
+
return Promise.resolve()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
href: computed(() => resolvedRoute.value.href),
|
|
108
|
+
route: computed(() => resolvedRoute.value.route),
|
|
109
|
+
isExactActive,
|
|
110
|
+
isActive,
|
|
111
|
+
navigate
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getCurrentInstance } from 'kdu'
|
|
2
|
+
|
|
3
|
+
// dev only warn if no current instance
|
|
4
|
+
|
|
5
|
+
export function throwNoCurrentInstance (method) {
|
|
6
|
+
if (!getCurrentInstance()) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
`[kdu-router]: Missing current instance. ${method}() must be called inside <script setup> or setup().`
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
}
|