@@ -7,21 +7,26 @@ const queryStringRE = /\?.*$/
77// HTML5 history mode
88export default function ( Vue ) {
99
10- const _ = Vue . util
1110 const urlParser = document . createElement ( 'a' )
11+ const {
12+ bind,
13+ isObject,
14+ addClass,
15+ removeClass
16+ } = Vue . util
1217
1318 Vue . directive ( 'link' , {
1419
1520 bind ( ) {
16- let vm = this . vm
21+ const vm = this . vm
1722 /* istanbul ignore if */
1823 if ( ! vm . $route ) {
19- warn (
20- 'v-link can only be used inside a ' +
21- 'router-enabled app.'
22- )
24+ warn ( 'v-link can only be used inside a router-enabled app.' )
2325 return
2426 }
27+ this . router = vm . $route . router
28+ // update things when the route changes
29+ this . unwatch = vm . $watch ( '$route' , bind ( this . onRouteUpdate , this ) )
2530 // no need to handle click if link expects to be opened
2631 // in a new window/tab.
2732 /* istanbul ignore if */
@@ -30,83 +35,99 @@ export default function (Vue) {
3035 return
3136 }
3237 // handle click
33- let router = vm . $route . router
34- this . handler = ( e ) => {
35- // don't redirect with control keys
36- if ( e . metaKey || e . ctrlKey || e . shiftKey ) return
37- // don't redirect when preventDefault called
38- if ( e . defaultPrevented ) return
39- // don't redirect on right click
40- if ( e . button !== 0 ) return
38+ this . el . addEventListener ( 'click' , bind ( this . onClick , this ) )
39+ } ,
40+
41+ update ( target ) {
42+ this . target = target
43+ if ( isObject ( target ) ) {
44+ this . append = target . append
45+ this . exact = target . exact
46+ this . prevActiveClass = this . activeClass
47+ this . activeClass = target . activeClass
48+ }
49+ this . onRouteUpdate ( this . vm . $route )
50+ } ,
4151
42- const target = this . target
43- const go = ( target ) => {
44- e . preventDefault ( )
45- if ( target != null ) {
46- router . go ( target )
47- }
52+ onClick ( e ) {
53+ // don't redirect with control keys
54+ if ( e . metaKey || e . ctrlKey || e . shiftKey ) return
55+ // don't redirect when preventDefault called
56+ if ( e . defaultPrevented ) return
57+ // don't redirect on right click
58+ if ( e . button !== 0 ) return
59+
60+ const target = this . target
61+ const go = ( target ) => {
62+ e . preventDefault ( )
63+ if ( target != null ) {
64+ this . router . go ( target )
4865 }
66+ }
4967
50- if ( this . el . tagName === 'A' || e . target === this . el ) {
51- // v-link on <a v-link="'path'">
52- if ( sameOrigin ( this . el , target ) ) {
53- go ( target )
54- } else if ( typeof target === 'string' ) {
55- window . location . href = target
56- }
57- } else {
58- // v-link delegate on <div v-link>
59- var el = e . target
60- while ( el && el . tagName !== 'A' && el !== this . el ) {
61- el = el . parentNode
62- }
63- if ( ! el ) return
64- if ( ! sameOrigin ( el , target ) && typeof target === 'string' ) {
65- window . location . href = target
66- }
67- if ( el . tagName !== 'A' || ! el . href ) {
68- // allow not anchor
69- go ( target )
70- } else if ( sameOrigin ( el , target ) ) {
71- go ( {
72- path : el . pathname ,
73- replace : target && target . replace ,
74- append : target && target . append
75- } )
76- }
68+ if ( this . el . tagName === 'A' || e . target === this . el ) {
69+ // v-link on <a v-link="'path'">
70+ if ( sameOrigin ( this . el , target ) ) {
71+ go ( target )
72+ } else if ( typeof target === 'string' ) {
73+ window . location . href = target
74+ }
75+ } else {
76+ // v-link delegate on <div v-link>
77+ var el = e . target
78+ while ( el && el . tagName !== 'A' && el !== this . el ) {
79+ el = el . parentNode
80+ }
81+ if ( ! el ) return
82+ if ( ! sameOrigin ( el , target ) && typeof target === 'string' ) {
83+ window . location . href = target
84+ }
85+ if ( el . tagName !== 'A' || ! el . href ) {
86+ // allow not anchor
87+ go ( target )
88+ } else if ( sameOrigin ( el , target ) ) {
89+ go ( {
90+ path : el . pathname ,
91+ replace : target && target . replace ,
92+ append : target && target . append
93+ } )
7794 }
7895 }
79- this . el . addEventListener ( 'click' , this . handler )
80- // manage active link class
81- this . unwatch = vm . $watch (
82- '$route.path' ,
83- _ . bind ( this . updateClasses , this )
84- )
8596 } ,
8697
87- update ( path ) {
88- let router = this . vm . $route . router
89- let append
90- this . target = path
91- if ( _ . isObject ( path ) ) {
92- append = path . append
93- this . exact = path . exact
94- this . prevActiveClass = this . activeClass
95- this . activeClass = path . activeClass
98+ onRouteUpdate ( route ) {
99+ // router._stringifyPath is dependent on current route
100+ // and needs to be called again whenver route changes.
101+ var newPath = this . router . _stringifyPath ( this . target )
102+ if ( this . path !== newPath ) {
103+ this . path = newPath
104+ this . updateActiveMatch ( )
105+ this . updateHref ( )
96106 }
97- path = this . path = router . _stringifyPath ( path )
98- this . activeRE = path && ! this . exact
107+ this . updateClasses ( route . path )
108+ } ,
109+
110+ updateActiveMatch ( ) {
111+ this . activeRE = this . path && ! this . exact
99112 ? new RegExp (
100113 '^' +
101- path . replace ( / \/ $ / , '' ) . replace ( regexEscapeRE , '\\$&' ) +
114+ this . path . replace ( / \/ $ / , '' ) . replace ( regexEscapeRE , '\\$&' ) +
102115 '(\\/|$)'
103116 )
104117 : null
105- this . updateClasses ( this . vm . $route . path )
106- let isAbsolute = path . charAt ( 0 ) === '/'
118+ } ,
119+
120+ updateHref ( ) {
121+ if ( this . target && this . target . name ) {
122+ this . el . href = '#' + this . target . name
123+ return
124+ }
125+ const path = this . path
126+ const router = this . router
127+ const isAbsolute = path . charAt ( 0 ) === '/'
107128 // do not format non-hash relative paths
108- let href = path && ( router . mode === 'hash' || isAbsolute )
109- ? router . history . formatPath ( path , append )
129+ const href = path && ( router . mode === 'hash' || isAbsolute )
130+ ? router . history . formatPath ( path , this . append )
110131 : path
111132 if ( this . el . tagName === 'A' ) {
112133 if ( href ) {
@@ -118,36 +139,31 @@ export default function (Vue) {
118139 } ,
119140
120141 updateClasses ( path ) {
121- let el = this . el
122- let router = this . vm . $route . router
123- let activeClass = this . activeClass || router . _linkActiveClass
142+ const el = this . el
143+ const activeClass = this . activeClass || this . router . _linkActiveClass
124144 // clear old class
125145 if ( this . prevActiveClass !== activeClass ) {
126- _ . removeClass ( el , this . prevActiveClass )
146+ removeClass ( el , this . prevActiveClass )
127147 }
128148 // remove query string before matching
129- let dest = this . path . replace ( queryStringRE , '' )
149+ const dest = this . path . replace ( queryStringRE , '' )
130150 path = path . replace ( queryStringRE , '' )
131151 // add new class
132152 if ( this . exact ) {
133- if (
134- dest === path ||
135- (
136- // also allow additional trailing slash
137- dest . charAt ( dest . length - 1 ) !== '/' &&
138- dest === path . replace ( trailingSlashRE , '' )
139- )
140- ) {
141- _ . addClass ( el , activeClass )
153+ if ( dest === path || (
154+ // also allow additional trailing slash
155+ dest . charAt ( dest . length - 1 ) !== '/' &&
156+ dest === path . replace ( trailingSlashRE , '' )
157+ ) ) {
158+ addClass ( el , activeClass )
142159 } else {
143- _ . removeClass ( el , activeClass )
160+ removeClass ( el , activeClass )
144161 }
145162 } else {
146- if ( this . activeRE &&
147- this . activeRE . test ( path ) ) {
148- _ . addClass ( el , activeClass )
163+ if ( this . activeRE && this . activeRE . test ( path ) ) {
164+ addClass ( el , activeClass )
149165 } else {
150- _ . removeClass ( el , activeClass )
166+ removeClass ( el , activeClass )
151167 }
152168 }
153169 } ,
0 commit comments