diff --git a/examples/scroll-behavior/app.js b/examples/scroll-behavior/app.js index 81a539f0c..afdccb049 100644 --- a/examples/scroll-behavior/app.js +++ b/examples/scroll-behavior/app.js @@ -37,7 +37,8 @@ const scrollBehavior = function (to, from, savedPosition) { position.offset = { y: 100 } } - if (document.querySelector(to.hash)) { + // bypass #1number check + if (/^#\d/.test(to.hash) || document.querySelector(to.hash)) { return position } @@ -87,6 +88,7 @@ new Vue({
  • /bar
  • /bar#anchor
  • /bar#anchor2
  • +
  • /bar#1number
  • diff --git a/src/util/scroll.js b/src/util/scroll.js index ec949c062..1d444f3ec 100644 --- a/src/util/scroll.js +++ b/src/util/scroll.js @@ -45,20 +45,27 @@ export function handleScroll ( // wait until re-render finishes before scrolling router.app.$nextTick(() => { const position = getScrollPosition() - const shouldScroll = behavior.call(router, to, from, isPop ? position : null) + const shouldScroll = behavior.call( + router, + to, + from, + isPop ? position : null + ) if (!shouldScroll) { return } if (typeof shouldScroll.then === 'function') { - shouldScroll.then(shouldScroll => { - scrollToPosition((shouldScroll: any), position) - }).catch(err => { - if (process.env.NODE_ENV !== 'production') { - assert(false, err.toString()) - } - }) + shouldScroll + .then(shouldScroll => { + scrollToPosition((shouldScroll: any), position) + }) + .catch(err => { + if (process.env.NODE_ENV !== 'production') { + assert(false, err.toString()) + } + }) } else { scrollToPosition(shouldScroll, position) } @@ -114,12 +121,22 @@ function isNumber (v: any): boolean { return typeof v === 'number' } +const hashStartsWithNumberRE = /^#\d/ + function scrollToPosition (shouldScroll, position) { const isObject = typeof shouldScroll === 'object' if (isObject && typeof shouldScroll.selector === 'string') { - const el = document.querySelector(shouldScroll.selector) + // getElementById would still fail if the selector contains a more complicated query like #main[data-attr] + // but at the same time, it doesn't make much sense to select an element with an id and an extra selector + const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line + ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line + : document.querySelector(shouldScroll.selector) + if (el) { - let offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {} + let offset = + shouldScroll.offset && typeof shouldScroll.offset === 'object' + ? shouldScroll.offset + : {} offset = normalizeOffset(offset) position = getElementPosition(el, offset) } else if (isValidPosition(shouldScroll)) { diff --git a/test/e2e/specs/scroll-behavior.js b/test/e2e/specs/scroll-behavior.js index 9ececb493..6cc371fee 100644 --- a/test/e2e/specs/scroll-behavior.js +++ b/test/e2e/specs/scroll-behavior.js @@ -11,7 +11,7 @@ module.exports = { browser .url('http://localhost:8080/scroll-behavior/') .waitForElementVisible('#app', 1000) - .assert.count('li a', 5) + .assert.count('li a', 6) .assert.containsText('.view', 'home') .execute(function () { @@ -117,6 +117,16 @@ module.exports = { null, 'scroll to anchor with offset' ) + .execute(function () { + document.querySelector('li:nth-child(6) a').click() + }) + .assert.evaluate( + function () { + return document.getElementById('1number').getBoundingClientRect().top < 1 + }, + null, + 'scroll to anchor that starts with number' + ) .end() } }