Skip to content

Commit 3144503

Browse files
committed
v-link-active + tests
1 parent d55d7ad commit 3144503

File tree

3 files changed

+101
-4
lines changed

3 files changed

+101
-4
lines changed

src/directives/link.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ export default function (Vue) {
1515
removeClass
1616
} = Vue.util
1717

18+
Vue.directive('link-active', {
19+
bind () {
20+
this.el.__v_link_active = true
21+
}
22+
})
23+
1824
Vue.directive('link', {
1925

2026
bind () {
@@ -36,6 +42,16 @@ export default function (Vue) {
3642
}
3743
// handle click
3844
this.el.addEventListener('click', bind(this.onClick, this))
45+
// check if active classes should be applied to a different element
46+
this.activeEl = this.el
47+
var parent = this.el.parentNode
48+
while (parent) {
49+
if (parent.__v_link_active) {
50+
this.activeEl = parent
51+
break
52+
}
53+
parent = parent.parentNode
54+
}
3955
},
4056

4157
update (target) {
@@ -111,7 +127,10 @@ export default function (Vue) {
111127
this.activeRE = this.path && !this.exact
112128
? new RegExp(
113129
'^' +
114-
this.path.replace(/\/$/, '').replace(regexEscapeRE, '\\$&') +
130+
this.path
131+
.replace(/\/$/, '')
132+
.replace(queryStringRE, '')
133+
.replace(regexEscapeRE, '\\$&') +
115134
'(\\/|$)'
116135
)
117136
: null
@@ -140,7 +159,7 @@ export default function (Vue) {
140159
},
141160

142161
updateClasses (path) {
143-
const el = this.el
162+
const el = this.activeEl
144163
const activeClass = this.activeClass || this.router._linkActiveClass
145164
// clear old class
146165
if (this.prevActiveClass !== activeClass) {

src/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,9 +546,10 @@ class Router {
546546
if (path.name) {
547547
const extend = Vue.util.extend
548548
const currentParams = this._currentTransition.to.params
549+
const targetParams = path.params || {}
549550
const params = currentParams
550-
? extend(extend({}, currentParams), path.params)
551-
: path.params || {}
551+
? extend(extend({}, currentParams), targetParams)
552+
: targetParams
552553
if (path.query) {
553554
params.queryParams = path.query
554555
}

test/unit/specs/core.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,83 @@ describe('Core', function () {
381381
})
382382
})
383383

384+
it('v-link active classes with named routes', function (done) {
385+
router = new Router({
386+
abstract: true,
387+
linkActiveClass: 'active'
388+
})
389+
router.map({
390+
'/a/:id': {
391+
component: {},
392+
subRoutes: {
393+
'b/:bid': {
394+
name: 'b',
395+
component: {}
396+
}
397+
}
398+
}
399+
})
400+
var App = Vue.extend({
401+
replace: false,
402+
data: function () {
403+
return { className: 'custom' }
404+
},
405+
template:
406+
'<a id="link" v-link="{ name: \'b\', params: { id: 1, bid: 2 }}">Link A</a>' +
407+
'<router-view></router-view>'
408+
})
409+
router.start(App, el)
410+
el = router.app.$el
411+
var link = el.querySelector('#link')
412+
expect(link.className).toBe('')
413+
router.go('/a/1/b/1')
414+
nextTick(function () {
415+
expect(link.className).toBe('')
416+
router.go({ name: 'b', params: { bid: 2 }})
417+
nextTick(function () {
418+
expect(link.className).toBe('active')
419+
expect(router._currentRoute.path).toBe('/a/1/b/2')
420+
done()
421+
})
422+
})
423+
})
424+
425+
it('v-link active classes with v-link-active', function (done) {
426+
router = new Router({
427+
abstract: true,
428+
linkActiveClass: 'active'
429+
})
430+
var App = Vue.extend({
431+
replace: false,
432+
template:
433+
'<ul>' +
434+
'<li id="link-a" v-link-active>' +
435+
'<a v-link="{ path: \'/a\' }">Link A</a>' +
436+
'</li>' +
437+
'<li id="link-b" v-link-active>' +
438+
'<a v-link="{ path: \'/b\' }">Link B</a>' +
439+
'</li>' +
440+
'</ul>'
441+
})
442+
router.start(App, el)
443+
el = router.app.$el
444+
var linkA = el.querySelector('#link-a')
445+
var linkB = el.querySelector('#link-b')
446+
expect(linkA.className).toBe('')
447+
expect(linkB.className).toBe('')
448+
router.go('/a')
449+
nextTick(function () {
450+
expect(linkA.className).toBe('active')
451+
expect(linkB.className).toBe('')
452+
router.go('/b')
453+
nextTick(function () {
454+
expect(linkA.className).toBe('')
455+
expect(linkB.className).toBe('active')
456+
done()
457+
})
458+
})
459+
})
460+
384461
it('v-link relative querystring', function (done) {
385462
router = new Router({ abstract: true })
386463
router.map({

0 commit comments

Comments
 (0)