Skip to content

Commit ea35594

Browse files
committed
feat: useRoute and useRouter
1 parent 337bde7 commit ea35594

File tree

8 files changed

+289
-27
lines changed

8 files changed

+289
-27
lines changed

examples/composables/app.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Vue, { defineComponent, watch, ref, onUnmounted } from 'vue'
2+
import VueRouter from 'vue-router'
3+
import { useRoute, useRouter } from 'vue-router/composables'
4+
5+
Vue.use(VueRouter)
6+
7+
const Home = defineComponent({
8+
setup () {
9+
const route = useRoute()
10+
const router = useRouter()
11+
12+
// should be /
13+
const startRoute = route.fullPath
14+
15+
console.log('got to Home', startRoute)
16+
17+
const watchCount = ref(0)
18+
19+
watch(() => route.query.n, () => {
20+
console.log('watched')
21+
watchCount.value++
22+
})
23+
24+
onUnmounted(() => {
25+
console.log('unmounted')
26+
})
27+
28+
function navigate () {
29+
router.push({ query: { n: 1 + (Number(route.query.n) || 0) }})
30+
}
31+
return { route, navigate, watchCount, startRoute }
32+
},
33+
template: `
34+
<div>
35+
<h2>Home</h2>
36+
<p id="start-route">{{ startRoute }}</p>
37+
<p id='watch-count'>{{ watchCount }}</p>
38+
<p id="fullpath">{{ route.fullPath }}</p>
39+
<button id="nav" @click="navigate">Navigate</button>
40+
</div>
41+
`
42+
})
43+
44+
const About = defineComponent({
45+
setup () {
46+
const route = useRoute()
47+
return { route }
48+
},
49+
template: `
50+
<div>
51+
<h2>About</h2>
52+
<p id="fullpath">{{ route.fullPath }}</p>
53+
</div>
54+
`
55+
})
56+
57+
const router = new VueRouter({
58+
mode: 'history',
59+
base: __dirname,
60+
routes: [
61+
{ path: '/', component: Home },
62+
{ path: '/about', component: About }
63+
]
64+
})
65+
66+
new Vue({
67+
router,
68+
template: `
69+
<div id="app">
70+
<h1>Basic</h1>
71+
<ul>
72+
<li><router-link to="/">/</router-link></li>
73+
<li><router-link to="/about">/foo</router-link></li>
74+
</ul>
75+
<router-view class="view"></router-view>
76+
</div>
77+
`
78+
}).$mount('#app')

examples/composables/index.html

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!DOCTYPE html>
2+
<link rel="stylesheet" href="/global.css">
3+
<a href="/">&larr; Examples index</a>
4+
<hr />
5+
<div id="app"></div>
6+
<script src="/__build__/shared.chunk.js"></script>
7+
<script src="/__build__/composables.js"></script>

examples/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ <h1>Vue Router Examples</h1>
3030
<li><a href="keepalive-view">Keepalive View</a></li>
3131
<li><a href="multi-app">Multiple Apps</a></li>
3232
<li><a href="restart-app">Restart App</a></li>
33+
<li><a href="composables">Composables</a></li>
3334
</ul>
3435
</body>
3536
</html>

examples/webpack.config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ module.exports = {
4949
resolve: {
5050
alias: {
5151
vue: 'vue/dist/vue.esm.js',
52-
'vue-router': path.join(__dirname, '..', 'src')
52+
'vue-router': path.join(__dirname, '..', 'src'),
53+
'vue-router/composables': path.join(__dirname, '..', 'src/composables.js')
5354
}
5455
},
5556

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@
9999
"rollup-watch": "^4.0.0",
100100
"selenium-server": "^3.141.59",
101101
"terser": "^4.2.0",
102-
"typescript": "^3.5.2",
103-
"vue": "^2.6.12",
102+
"typescript": "^4.7.0",
103+
"vue": "^2.7.0",
104104
"vue-loader": "^15.9.3",
105-
"vue-server-renderer": "^2.6.12",
106-
"vue-template-compiler": "^2.6.12",
105+
"vue-server-renderer": "^2.7.0",
106+
"vue-template-compiler": "^2.7.0",
107107
"vuepress": "^1.5.3",
108108
"vuepress-theme-vue": "^1.1.1",
109109
"webpack": "^4.35.2",

src/composables.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { getCurrentInstance, shallowReactive, effectScope } from 'vue'
2+
3+
export function useRouter () {
4+
const i = getCurrentInstance()
5+
if (process.env.NODE_ENV !== 'production' && !i) {
6+
throwNoCurrentInstance('useRouter')
7+
}
8+
9+
return i.proxy.$root.$router
10+
}
11+
12+
export function useRoute () {
13+
const i = getCurrentInstance()
14+
if (process.env.NODE_ENV !== 'production' && !i) {
15+
throwNoCurrentInstance('useRoute')
16+
}
17+
18+
const root = i.proxy.$root
19+
if (!root._$route) {
20+
const route = effectScope(true).run(
21+
() => shallowReactive(Object.assign({}, root.$router.currentRoute))
22+
)
23+
root._$route = route
24+
25+
root.$router.afterEach(to => {
26+
Object.assign(route, to)
27+
})
28+
}
29+
30+
return root._$route
31+
}
32+
33+
// TODO:
34+
// export function useLink () {}
35+
36+
// TODO:
37+
// export function onBeforeRouteUpdate () {}
38+
39+
// TODO:
40+
// export function onBeforeRouteLeave () {}
41+
42+
function throwNoCurrentInstance (method) {
43+
throw new Error(
44+
`[vue-router]: Missing current instance. ${method}() must be called inside <script setup> or setup().`
45+
)
46+
}

test/e2e/specs/composables.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const bsStatus = require('../browserstack-send-status')
2+
3+
module.exports = {
4+
...bsStatus(),
5+
6+
'@tags': ['history'],
7+
8+
'useRoute() + useRouter()': function (browser) {
9+
browser
10+
.url('http://localhost:8080/composables/')
11+
.waitForElementVisible('#app', 1000)
12+
.assert.count('li', 2)
13+
.assert.count('li a', 2)
14+
.assert.containsText('.view', 'Home')
15+
16+
.click('li:nth-child(2) a')
17+
.assert.containsText('.view', 'About')
18+
.click('li:nth-child(1) a')
19+
.assert.containsText('.view', 'Home')
20+
.assert.containsText('#start-route', '/')
21+
.assert.containsText('#fullpath', '/')
22+
23+
.click('button#nav')
24+
.assert.containsText('#fullpath', '/?n=1')
25+
26+
.end()
27+
}
28+
29+
}

0 commit comments

Comments
 (0)