通过 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 这样的使用场景)。此时,可以考虑如下的几种方案去绕过这一限制:
- 用
\
的方式处理:
字符(同 CSS 的处理方案),比如a:b
变为#a\:b
(当然,在 JavaScript 实际使用的时候,需要注意字符串内\
本身的 Escape,最终的结果:document.querySelector('#a\\:b')
); - 使用 Unicode 来 Escape,比如将
:
改写成\3A
,对于 JavaScript 来说可能需要一次额外的 Escape,最终写法是document.querySelector('#\\3A')
- 使用
[id=""]
的方案进行 ID 的选取,如document.querySelector('[id="a:b"]')
。因为属性选择器本身是在寻找字符串,因此其中就算有:
这样的特殊字符,也不会有问题;
参考
针对 CSS Selector 的 Escape 方案(第一种和第二种),可以参考这篇文章,其中还详细列举了 CSS 中的特殊字符。
unique-selector 使用了第三种方案,具体代码可以参考这里。