querySelector with escape

JavaScript

通过 ID 选择 DOM 上的节点时,一般常用的 API 是 document.getElementById 或者更普适的 document.querySelector

问题

其中,对于后者(document.querySelector)来说,需要额外考虑一些特殊 ID 的处理。

举例来说,如果一个 ID 是以数字开头的,那么可以通过 document.getElementById 获取到,但是使用 document.querySelector 却会出现报错:

const div = document.createElement('div');
div.id = '1';
document.body.appendChild(div);

document.getElementById('1'); // => div
document.querySelector('#1'); // => Error: '#1' is not a valid selector.

同理,如果 ID 带有 : 字符,也会出现上述的问题。

这是因为,这样的命名方式,并不是合法的 CSS Selector。换句话说,不仅仅是 JavaScript API 无法生效,CSS 也无法直接生效。: 的情况很好理解,ID 中存在这样的字符,就无法很好的和 Pseudo Class 进行区分了(比如 :before)。

解决方案

要处理这样的情况,最简单的方案是使用 document.getElementById。但是,在一些场景下,可能需要生成 CSS Selector 来标记元素,方便统一的存储和使用(比如 unique-selector 这样的使用场景)。此时,可以考虑如下的几种方案去绕过这一限制:

  1. \ 的方式处理 : 字符(同 CSS 的处理方案),比如 a:b 变为 #a\:b(当然,在 JavaScript 实际使用的时候,需要注意字符串内 \ 本身的 Escape,最终的结果:document.querySelector('#a\\:b'));
  2. 使用 Unicode 来 Escape,比如将 : 改写成 \3A,对于 JavaScript 来说可能需要一次额外的 Escape,最终写法是 document.querySelector('#\\3A')
  3. 使用 [id=""] 的方案进行 ID 的选取,如 document.querySelector('[id="a:b"]')。因为属性选择器本身是在寻找字符串,因此其中就算有 : 这样的特殊字符,也不会有问题;

参考

针对 CSS Selector 的 Escape 方案(第一种和第二种),可以参考这篇文章,其中还详细列举了 CSS 中的特殊字符。

unique-selector 使用了第三种方案,具体代码可以参考这里