diff --git a/examples/index.html b/examples/index.html
index f2bdf7225..e024d8295 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -17,6 +17,7 @@
Vue Router Examples
Redirect
Route Props
Route Alias
+ Router Link
Transitions
Data Fetching
Navigation Guards
diff --git a/examples/router-link/app.js b/examples/router-link/app.js
new file mode 100644
index 000000000..f39a9cd5c
--- /dev/null
+++ b/examples/router-link/app.js
@@ -0,0 +1,52 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+
+Vue.use(VueRouter)
+
+const Home = { template: '{{ $route.fullPath }}
' }
+const Sub = { template: 'Nested View
' }
+const SubNested = { template: 'Sub
{{ $route.params.id }}
' }
+
+const CustomLink = {
+ props: ['disabled', 'n'],
+ template: ''
+}
+
+Vue.component('CustomLink', CustomLink)
+
+const router = new VueRouter({
+ mode: 'history',
+ base: __dirname,
+ routes: [
+ { path: '/', component: Home },
+ { path: '/other', component: Home },
+ {
+ path: '/sub/:id',
+ component: Sub,
+ children: [
+ { path: 'nested1', component: SubNested, name: 'sub1' },
+ { path: 'nested2', component: SubNested, name: 'sub2' }
+ ]
+ }
+ ]
+})
+
+new Vue({
+ router,
+ template: `
+
+
Router Link lol
+
+ - /
+ - CustomLink
+ - /
+ - /other
+ - /sub/1
+ - /sub/2
+ - /sub/:id/nested1
+ - /sub/:id/nested2
+
+
+
+ `
+}).$mount('#app')
diff --git a/examples/router-link/index.html b/examples/router-link/index.html
new file mode 100644
index 000000000..abe63b876
--- /dev/null
+++ b/examples/router-link/index.html
@@ -0,0 +1,14 @@
+
+
+
+← Examples index
+
+
+
diff --git a/src/components/link.js b/src/components/link.js
index a6fbec0f6..0655e339b 100644
--- a/src/components/link.js
+++ b/src/components/link.js
@@ -9,6 +9,7 @@ const eventTypes: Array = [String, Array]
export default {
name: 'RouterLink',
+ functional: true,
props: {
to: {
type: toTypes,
@@ -28,10 +29,10 @@ export default {
default: 'click'
}
},
- render (h: Function) {
- const router = this.$router
- const current = this.$route
- const { location, route, href } = router.resolve(this.to, current, this.append)
+ render (h: Function, { props, children, parent, data }: any) {
+ const router = parent.$router
+ const current = parent.$route
+ const { location, route, href } = router.resolve(props.to, current, props.append)
const classes = {}
const globalActiveClass = router.options.linkActiveClass
@@ -43,24 +44,25 @@ export default {
const exactActiveClassFallback = globalExactActiveClass == null
? 'router-link-exact-active'
: globalExactActiveClass
- const activeClass = this.activeClass == null
+ const activeClass = props.activeClass == null
? activeClassFallback
- : this.activeClass
- const exactActiveClass = this.exactActiveClass == null
+ : props.activeClass
+ const exactActiveClass = props.exactActiveClass == null
? exactActiveClassFallback
- : this.exactActiveClass
+ : props.exactActiveClass
const compareTarget = location.path
? createRoute(null, location, null, router)
: route
+ const extend = _Vue.util.extend
classes[exactActiveClass] = isSameRoute(current, compareTarget)
- classes[activeClass] = this.exact
+ classes[activeClass] = props.exact
? classes[exactActiveClass]
: isIncludedRoute(current, compareTarget)
const handler = e => {
if (guardEvent(e)) {
- if (this.replace) {
+ if (props.replace) {
router.replace(location)
} else {
router.push(location)
@@ -68,27 +70,24 @@ export default {
}
}
+ data.class = extend(data.class || {}, classes)
+
const on = { click: guardEvent }
- if (Array.isArray(this.event)) {
- this.event.forEach(e => { on[e] = handler })
+ if (Array.isArray(props.event)) {
+ props.event.forEach(e => { on[e] = handler })
} else {
- on[this.event] = handler
- }
-
- const data: any = {
- class: classes
+ on[props.event] = handler
}
- if (this.tag === 'a') {
+ if (props.tag === 'a') {
data.on = on
data.attrs = { href }
} else {
// find the first child and apply listener and href
- const a = findAnchor(this.$slots.default)
+ const a = findAnchor(children)
if (a) {
// in case the is a static node
a.isStatic = false
- const extend = _Vue.util.extend
const aData = a.data = extend({}, a.data)
aData.on = on
const aAttrs = a.data.attrs = extend({}, a.data.attrs)
@@ -99,7 +98,7 @@ export default {
}
}
- return h(this.tag, data, this.$slots.default)
+ return h(props.tag, data, children)
}
}
diff --git a/test/e2e/specs/router-link.js b/test/e2e/specs/router-link.js
new file mode 100644
index 000000000..4f89f94e3
--- /dev/null
+++ b/test/e2e/specs/router-link.js
@@ -0,0 +1,47 @@
+// This test should be done in a unit test once we migrate to jest
+
+module.exports = {
+ 'router link': function (browser) {
+ browser
+ .url('http://localhost:8080/router-link/')
+ .waitForElementVisible('#app', 1000)
+ // assert correct href with base
+ .assert.cssClassPresent('li:nth-child(1) a', 'custom-class')
+ .assert.cssClassPresent('li:nth-child(1) a', 'otherClass')
+ .assert.cssClassPresent('li:nth-child(1) a', 'router-link-active')
+
+ .assert.containsText('li:nth-child(2) button', 'N CustomLink')
+
+ .assert.attributeContains('li:nth-child(3) a', 'style', 'color:')
+ .assert.attributeContains('li:nth-child(3) a', 'style', 'font-size: 8px')
+
+ .click('li:nth-child(5) a')
+ .assert.attributeContains('li:nth-child(7) a', 'href', '/router-link/sub/1/nested1')
+ .assert.attributeContains('li:nth-child(8) a', 'href', '/router-link/sub/1/nested2')
+ .click('li:nth-child(6) a')
+ .assert.attributeContains('li:nth-child(7) a', 'href', '/router-link/sub/2/nested1')
+ .assert.attributeContains('li:nth-child(8) a', 'href', '/router-link/sub/2/nested2')
+
+ browser.expect.element('li:nth-child(2) button').to.have.attribute('disabled')
+
+ browser.end()
+
+ function assertActiveLinks (n, activeA, activeLI, exactActiveA, exactActiveLI) {
+ browser.click(`li:nth-child(${n}) a`)
+ activeA.forEach(i => {
+ browser.assert.cssClassPresent(`li:nth-child(${i}) a`, 'router-link-active')
+ })
+ activeLI && activeLI.forEach(i => {
+ browser.assert.cssClassPresent(`li:nth-child(${i})`, 'router-link-active')
+ })
+ exactActiveA.forEach(i => {
+ browser.assert.cssClassPresent(`li:nth-child(${i}) a`, 'router-link-exact-active')
+ .assert.cssClassPresent(`li:nth-child(${i}) a`, 'router-link-active')
+ })
+ exactActiveLI && exactActiveLI.forEach(i => {
+ browser.assert.cssClassPresent(`li:nth-child(${i})`, 'router-link-exact-active')
+ .assert.cssClassPresent(`li:nth-child(${i})`, 'router-link-active')
+ })
+ }
+ }
+}