]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat(link): add initial version router-link
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 7 Jun 2019 08:56:12 +0000 (10:56 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Fri, 7 Jun 2019 08:56:12 +0000 (10:56 +0200)
explorations/html5.html
explorations/html5.ts
src/components/Link.ts [new file with mode: 0644]
src/index.ts
src/matcher.ts
src/router.ts

index c2cd7fb725b6962f0268bb660c4cec79b243513c..0507fe49429318e7d52b7251cbb27a62c83d2a5a 100644 (file)
@@ -9,10 +9,28 @@
   <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>
index 40c6343e86167824c7c2aebdc98a8bb6c45aa39f..75edcbb58415acd34553b4a595a61fd8c29af563 100644 (file)
@@ -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 (file)
index 0000000..f24373f
--- /dev/null
@@ -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
index db8c4e6e700fa6071772c4214f46639d58ab019a..d974013b777408ba4b8ff0d250d79350a7a19616 100644 (file)
@@ -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<void> = Vue => {
   Vue.mixin({
@@ -46,6 +47,8 @@ const plugin: PluginFunction<void> = Vue => {
 
   // @ts-ignore
   Vue.component('RouterView', View)
+  // @ts-ignore
+  Vue.component('RouterLink', Link)
   // Vue.component('RouterLink', Link)
 
   const strats = Vue.config.optionMergeStrategies
index f5cdf4be678a15d85b006dbcfaa731df99cd20e0..e8944a3b33d3292e743b8631b939f16e8ec15676 100644 (file)
@@ -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
 
index ed0d399427c0c9c8b995120f51a6eee4e493ccd2..9f304567c87b2449f3e532ba04c19f5c59cd6d42 100644 (file)
@@ -77,7 +77,7 @@ export class Router {
   }
 
   // TODO: rename to resolveLocation?
-  private matchLocation(
+  matchLocation(
     location: MatcherLocation & Required<RouteQueryAndHash>,
     currentLocation: RouteLocationNormalized,
     redirectedFrom?: RouteLocationNormalized