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() } }