]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix: allow arbitrary selectors starting with #
authorEduardo San Martin Morote <posva13@gmail.com>
Tue, 26 May 2020 14:58:07 +0000 (16:58 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Tue, 26 May 2020 15:16:30 +0000 (17:16 +0200)
BREAKING CHANGE: It is now necessary to escape id selectors like
explained at https://mathiasbynens.be/notes/css-escapes. This was
necessary to allow selectors like `#container > child`.

e2e/scroll-behavior/index.ts
src/scrollBehavior.ts

index 5ba37ef50ec12ac1baa98ab167c0c4a84315f261..f98dbea8235ed39ad8606fa3dff5014c461f493d 100644 (file)
@@ -36,15 +36,14 @@ const scrollBehavior: ScrollBehavior = async function (
 
     // scroll to anchor by returning the selector
     if (to.hash) {
-      position = { selector: to.hash }
+      position = { selector: decodeURI(to.hash) }
 
       // specify offset of the element
       if (to.hash === '#anchor2') {
         position.offset = { y: 100 }
       }
 
-      // bypass #1number check
-      if (/^#\d/.test(to.hash) || document.querySelector(to.hash)) {
+      if (document.querySelector(position.selector)) {
         return position
       }
 
@@ -80,6 +79,7 @@ scrollWaiter.add()
 const app = createApp({
   setup() {
     return {
+      hashWithNumber: { path: '/bar', hash: '#\\31 number' },
       flushWaiter: scrollWaiter.flush,
       setupWaiter: scrollWaiter.add,
     }
@@ -99,7 +99,7 @@ const app = createApp({
         <li><router-link to="/bar">/bar</router-link></li>
         <li><router-link to="/bar#anchor">/bar#anchor</router-link></li>
         <li><router-link to="/bar#anchor2">/bar#anchor2</router-link></li>
-        <li><router-link to="/bar#1number">/bar#1number</router-link></li>
+        <li><router-link :to="hashWithNumber">/bar#1number</router-link></li>
       </ul>
       <router-view class="view" v-slot="{ Component, props }">
         <transition
index 8af9d6afa50b8b83c5dda87dd0e5aacd5eca4dbc..322543a6abf7fb84b671764a845ddb29d79f62c2 100644 (file)
@@ -68,26 +68,37 @@ export function scrollToPosition(position: ScrollPosition): void {
 
   if ('selector' in position) {
     /**
-     * `id`s can accept pretty much any characters, including CSS combinators like >
-     * or ~. It's still possible to retrieve elements using
+     * `id`s can accept pretty much any characters, including CSS combinators
+     * like `>` or `~`. It's still possible to retrieve elements using
      * `document.getElementById('~')` but it needs to be escaped when using
-     * `document.querySelector('#\\~')` for it to be valid. The only requirements
-     * for `id`s are them to be unique on the page and to not be empty (`id=""`).
-     * Because of that, when passing an `id` selector, it shouldn't have any other
-     * selector attached to it (like a class or an attribute) because it wouldn't
-     * have any effect anyway. We are therefore considering any selector starting
-     * with a `#` to be an `id` selector so we can directly use `getElementById`
-     * instead of `querySelector`, allowing users to write simpler selectors like:
-     * `#1-thing` or `#with~symbols` without having to manually escape them to valid
-     * CSS selectors: `#\31 -thing` and `#with\\~symbols`.
+     * `document.querySelector('#\\~')` for it to be valid. The only
+     * requirements for `id`s are them to be unique on the page and to not be
+     * empty (`id=""`). Because of that, when passing an id selector, it should
+     * be properly escaped for it to work with `querySelector`. We could check
+     * for the id selector to be simple (no CSS combinators `+ >~`) but that
+     * would make things inconsistent since they are valid characters for an
+     * `id` but would need to be escaped when using `querySelector`, breaking
+     * their usage and ending up in no selector returned. Selectors need to be
+     * escaped:
+     *
+     * - `#1-thing` becomes `#\31 -thing`
+     * - `#with~symbols` becomes `#with\\~symbols`
      *
      * - More information about  the topic can be found at
      *   https://mathiasbynens.be/notes/html5-id-class.
      * - Practical example: https://mathiasbynens.be/demo/html5-id
      */
-    const el = position.selector.startsWith('#')
-      ? document.getElementById(position.selector.slice(1))
-      : document.querySelector(position.selector)
+    if (__DEV__) {
+      try {
+        document.querySelector(position.selector)
+      } catch {
+        warn(
+          `The selector "${position.selector}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes.`
+        )
+      }
+    }
+
+    const el = document.querySelector(position.selector)
 
     if (!el) {
       __DEV__ &&