<body>
<div id="app">
<h2>{{ message }}</h2>
+ <pre>{{ $route }}</pre>
<label>
<input type="checkbox" onchange="cancel = !cancel" /> Cancel Next
Navigation
</label>
+ <ul>
+ <li>
+ <router-link to="/">/</router-link>
+ </li>
+ <li>
+ <router-link to="/users/5">/users/5</router-link>
+ </li>
+ <li>
+ <router-link
+ :to="{ name: 'user', params: { id: Number($route.params.id || 0) + 1 }}"
+ >/users/{{ Number($route.params.id || 0) + 1 }}</router-link
+ >
+ </li>
+ <!-- <li>
+ <router-link :to="{ name: 'docs' }">Doc with same id</router-link>
+ </li> -->
+ </ul>
<router-view></router-view>
</div>
</body>
routes: [
{ path: '/', component: Home },
{ path: '/users/:id', name: 'user', component: User },
+ { path: '/documents/:id', name: 'docs', component: User },
{ path: '/n/:n', name: 'increment', component },
{ path: '/multiple/:a/:b', name: 'user', component },
{
// h.replace('/bar')
// r.push('/about')
- await r.push({
- path: '/',
- })
-
- await r.push({
- name: 'user',
- params: {
- id: '6',
- },
- })
+ await r.push('/')
- await r.push({
- name: 'user',
- params: {
- id: '5',
- },
- })
+ // await r.push({
+ // name: 'user',
+ // params: {
+ // id: '6',
+ // },
+ // })
+
+ // await r.push({
+ // name: 'user',
+ // params: {
+ // id: '5',
+ // },
+ // })
// try {
// await r.push({
--- /dev/null
+import { Component } from 'vue'
+import { Router } from '../router'
+import { RouteLocationNormalized, RouteLocation } from '../types'
+
+const Link: Component = {
+ name: 'RouterLink',
+ props: {
+ to: {
+ type: [String, Object],
+ required: true,
+ },
+ },
+
+ render(h) {
+ // @ts-ignore
+ const router = this.$router as Router
+ // @ts-ignore
+ const from = this.$route as RouteLocationNormalized
+ // @ts-ignore
+ const to = this.to as RouteLocation
+ // @ts-ignore
+ let url: HistoryLocationNormalized
+ let location: RouteLocationNormalized
+ // TODO: refactor router code and use its function istead of having a copied version here
+ if (typeof to === 'string' || 'path' in to) {
+ // @ts-ignore
+ url = router.history.utils.normalizeLocation(to)
+ // TODO: should allow a non matching url to allow dynamic routing to work
+ location = router.matchLocation(url, from)
+ } else {
+ // named or relative route
+ // @ts-ignore
+ const query = router.history.utils.normalizeQuery(
+ to.query ? to.query : {}
+ )
+ const hash = to.hash || ''
+ // we need to resolve first
+ location = router.matchLocation({ ...to, query, hash }, from)
+ // intentionally drop current query and hash
+ // @ts-ignore
+ url = router.history.utils.normalizeLocation({
+ query,
+ hash,
+ ...location,
+ })
+ }
+ const route = router.matchLocation(url, from)
+
+ // TODO: active classes
+ // TODO: handle replace prop
+
+ const handler = (e: MouseEvent) => {
+ if (guardEvent(e)) {
+ router.push(route)
+ }
+ }
+
+ const on = { click: handler }
+
+ const data: any = {
+ on,
+ attrs: { href: route.fullPath },
+ }
+
+ // @ts-ignore
+ return h('a', data, this.$slots.default)
+ },
+}
+
+function guardEvent(e: MouseEvent) {
+ // don't redirect with control keys
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return
+ // don't redirect when preventDefault called
+ if (e.defaultPrevented) return
+ // don't redirect on right click
+ if (e.button !== undefined && e.button !== 0) return
+ // don't redirect if `target="_blank"`
+ // @ts-ignore
+ if (e.currentTarget && e.currentTarget.getAttribute) {
+ // @ts-ignore
+ const target = e.currentTarget.getAttribute('target')
+ if (/\b_blank\b/i.test(target)) return
+ }
+ // this may be a Weex event which doesn't have this method
+ if (e.preventDefault) {
+ e.preventDefault()
+ }
+ return true
+}
+
+export default Link
import { HTML5History } from './history/html5'
import { PluginFunction } from 'vue'
import View from './components/View'
+import Link from './components/Link'
const plugin: PluginFunction<void> = Vue => {
Vue.mixin({
// @ts-ignore
Vue.component('RouterView', View)
+ // @ts-ignore
+ Vue.component('RouterLink', Link)
// Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies