diff --git a/examples/basic/app.js b/examples/basic/app.js
index bafe7cbfb..3140f03ce 100644
--- a/examples/basic/app.js
+++ b/examples/basic/app.js
@@ -40,7 +40,11 @@ new Vue({
/bar
/é
+ /é?t=%ñ
+ /é#%25ñ
+ {{ $route.query.t }}
+ {{ $route.hash }}
`
diff --git a/examples/hash-mode/app.js b/examples/hash-mode/app.js
index f90da3255..b6d3adc66 100644
--- a/examples/hash-mode/app.js
+++ b/examples/hash-mode/app.js
@@ -10,7 +10,7 @@ Vue.use(VueRouter)
const Home = { template: 'home
' }
const Foo = { template: 'foo
' }
const Bar = { template: 'bar
' }
-const Unicode = { template: 'unicode
' }
+const Unicode = { template: 'unicode: {{ $route.params.unicode }}
' }
// 3. Create the router
const router = new VueRouter({
@@ -20,7 +20,8 @@ const router = new VueRouter({
{ path: '/', component: Home }, // all paths are defined without the hash.
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
- { path: '/é', component: Unicode }
+ { path: '/é', component: Unicode },
+ { path: '/é/:unicode', component: Unicode }
]
})
@@ -38,7 +39,12 @@ new Vue({
/bar
/bar
/é
+ /é/ñ
+ /é/ñ?t=%ñ
+ /é/ñ#é
+ {{ $route.query.t }}
+ {{ $route.hash }}
`
diff --git a/src/history/hash.js b/src/history/hash.js
index 330f2383c..16c94db0e 100644
--- a/src/history/hash.js
+++ b/src/history/hash.js
@@ -100,9 +100,25 @@ function ensureSlash (): boolean {
export function getHash (): string {
// We can't use window.location.hash here because it's not
// consistent across browsers - Firefox will pre-decode it!
- const href = window.location.href
+ let href = window.location.href
const index = href.indexOf('#')
- return index === -1 ? '' : decodeURI(href.slice(index + 1))
+ // empty path
+ if (index < 0) return ''
+
+ href = href.slice(index + 1)
+ // decode the hash but not the search or hash
+ // as search(query) is already decoded
+ // https://github.com/vuejs/vue-router/issues/2708
+ const searchIndex = href.indexOf('?')
+ if (searchIndex < 0) {
+ const hashIndex = href.indexOf('#')
+ if (hashIndex > -1) href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex)
+ else href = decodeURI(href)
+ } else {
+ if (searchIndex > -1) href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex)
+ }
+
+ return href
}
function getUrl (path) {
diff --git a/test/e2e/specs/basic.js b/test/e2e/specs/basic.js
index 78b6d8df5..ad2e5c00f 100644
--- a/test/e2e/specs/basic.js
+++ b/test/e2e/specs/basic.js
@@ -3,8 +3,8 @@ module.exports = {
browser
.url('http://localhost:8080/basic/')
.waitForElementVisible('#app', 1000)
- .assert.count('li', 5)
- .assert.count('li a', 5)
+ .assert.count('li', 7)
+ .assert.count('li a', 7)
// assert correct href with base
.assert.attributeContains('li:nth-child(1) a', 'href', '/basic/')
.assert.attributeContains('li:nth-child(2) a', 'href', '/basic/foo')
diff --git a/test/e2e/specs/hash-mode.js b/test/e2e/specs/hash-mode.js
index d32d4d0dd..554a17ee3 100644
--- a/test/e2e/specs/hash-mode.js
+++ b/test/e2e/specs/hash-mode.js
@@ -3,12 +3,14 @@ module.exports = {
browser
.url('http://localhost:8080/hash-mode/')
.waitForElementVisible('#app', 1000)
- .assert.count('li', 5)
- .assert.count('li a', 4)
+ .assert.count('li', 8)
+ .assert.count('li a', 7)
.assert.attributeContains('li:nth-child(1) a', 'href', '/hash-mode/#/')
.assert.attributeContains('li:nth-child(2) a', 'href', '/hash-mode/#/foo')
.assert.attributeContains('li:nth-child(3) a', 'href', '/hash-mode/#/bar')
.assert.attributeContains('li:nth-child(5) a', 'href', '/hash-mode/#/%C3%A9')
+ .assert.attributeContains('li:nth-child(6) a', 'href', '/hash-mode/#/%C3%A9/%C3%B1')
+ .assert.attributeContains('li:nth-child(7) a', 'href', '/hash-mode/#/%C3%A9/%C3%B1?t=%25%C3%B1')
.assert.containsText('.view', 'home')
.click('li:nth-child(2) a')
@@ -31,9 +33,24 @@ module.exports = {
.url('http://localhost:8080/hash-mode/#/foo')
.waitForElementVisible('#app', 1000)
.assert.containsText('.view', 'foo')
+ // direct visit encoded unicode
.url('http://localhost:8080/hash-mode/#/%C3%A9')
.waitForElementVisible('#app', 1000)
.assert.containsText('.view', 'unicode')
+ // direct visit raw unicode
+ .url('http://localhost:8080/hash-mode/#/%C3%A9/%C3%B1')
+ .waitForElementVisible('#app', 1000)
+ .assert.containsText('.view', 'unicode: ñ')
+ // TODO: Doesn't seem to work on PhantomJS
+ // .click('li:nth-child(7)')
+ // .assert.urlEquals('http://localhost:8080/hash-mode/#/%C3%A9/%C3%B1?t=%25')
+ // .assert.containsText('.view', 'unicode: ñ')
+ // .assert.containsText('#query-t', '%')
+ // direct visit
+ .url('http://localhost:8080/hash-mode/#/%C3%A9/%C3%B1?t=%25')
+ .waitForElementVisible('#app', 1000)
+ .assert.containsText('.view', 'unicode: ñ')
+ .assert.containsText('#query-t', '%')
.end()
}
}