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

    + + +
    + ` +}).$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') + }) + } + } +}