From: Eduardo San Martin Morote Date: Fri, 7 Jun 2019 08:56:12 +0000 (+0200) Subject: feat(link): add initial version router-link X-Git-Tag: v4.0.0-alpha.0~346 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b8283a27543fccf521becda68a59db4765647ad;p=thirdparty%2Fvuejs%2Frouter.git feat(link): add initial version router-link --- diff --git a/explorations/html5.html b/explorations/html5.html index c2cd7fb7..0507fe49 100644 --- a/explorations/html5.html +++ b/explorations/html5.html @@ -9,10 +9,28 @@

{{ message }}

+
{{ $route }}
+
diff --git a/explorations/html5.ts b/explorations/html5.ts index 40c6343e..75edcbb5 100644 --- a/explorations/html5.ts +++ b/explorations/html5.ts @@ -38,6 +38,7 @@ const router = new Router({ 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 }, { @@ -111,23 +112,21 @@ async function run() { // 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({ diff --git a/src/components/Link.ts b/src/components/Link.ts new file mode 100644 index 00000000..f24373fd --- /dev/null +++ b/src/components/Link.ts @@ -0,0 +1,91 @@ +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 diff --git a/src/index.ts b/src/index.ts index db8c4e6e..d974013b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import { Router } from './router' import { HTML5History } from './history/html5' import { PluginFunction } from 'vue' import View from './components/View' +import Link from './components/Link' const plugin: PluginFunction = Vue => { Vue.mixin({ @@ -46,6 +47,8 @@ const plugin: PluginFunction = Vue => { // @ts-ignore Vue.component('RouterView', View) + // @ts-ignore + Vue.component('RouterLink', Link) // Vue.component('RouterLink', Link) const strats = Vue.config.optionMergeStrategies diff --git a/src/matcher.ts b/src/matcher.ts index f5cdf4be..e8944a3b 100644 --- a/src/matcher.ts +++ b/src/matcher.ts @@ -135,7 +135,7 @@ export class RouterMatcher { if (!matcher) throw new NoRouteMatchError(currentLocation, location) name = matcher.record.name - params = location.params || {} // TODO: normalize params + params = location.params || currentLocation.params // TODO: normalize params path = matcher.resolve(params) // TODO: check missing params diff --git a/src/router.ts b/src/router.ts index ed0d3994..9f304567 100644 --- a/src/router.ts +++ b/src/router.ts @@ -77,7 +77,7 @@ export class Router { } // TODO: rename to resolveLocation? - private matchLocation( + matchLocation( location: MatcherLocation & Required, currentLocation: RouteLocationNormalized, redirectedFrom?: RouteLocationNormalized