JQuery选择器中含有冒号的ID处理差别的分析

问题提出

对于一个输入框, 若是其id中含有冒号(:),选择器使用须要有特殊写法, javascript

例如 id为下css

<input type="text" value="ddd" id="a:b">html

使用$(selector)直接使用#id值, 找不到DOMjava

console.log("#a:b")
console.log($("#a:b").length) // output 0jquery

 

通过探索可使用如下两个方法选择到DOM:css3

$("#a\\:b");浏览器

$("[id^='a:b']");app

其中第一种, 须要在冒号(:)前添加一个反斜杠(\), 某些同窗要问了,命名是两个反斜杠, 忽悠我?学习

请看下节介绍。spa

JS转义

js中的字符串语法须要占用一些元字符, 对于这些元字符若是须要想要在字符串中出现就须要使用转移:

转义表: FROM http://www.w3school.com.cn/js/js_special_characters.asp

代码 输出
\' 单引号
\" 双引号
\& 和号
\\ 反斜杠
\n 换行符
\r 回车符
\t 制表符
\b 退格符
\f 换页符

事实上,从上表中看以看出,不只仅是元字符须要显示才转义(" -> \"), 还有使用转移后能够将特定字符转义为另外含义的状况, 例如 n -> \n 变为换行符。

从学习上能够按照以下逻辑总体理解js转义:

一、 js字符串使用 单引号 或者 双引号 做为字符串的”括号”, 表示一个总体字符串, 引号内部为字符串内容,

二、 那么问题来了, 字符串内容中要想包括 引号, 怎么办?

三、 js设计者(Brendan Eich)考虑, 相似c语言中转义方法, 使用\x 方式来表示x, 即转义规则 \x == x, 这里x包括引号(‘ “)。

四、 既然使用了\x格式执行转义, 那字符串内容中要想包含\怎么办? 若是直接使用\, 则极可能跟其后面一个正常字符意外的转义。

五、 既然转义规则已定  \x == x, 那么\在字符串内容中存在的场景,正符合此规则, 规则应用效果为 \\ == \ 、

六、 最后还有一种场景, 存在不少控制字符(包括格式控制字符,例如\n、 和不可打印字符), 这些字符自己没有可打印字符的表现形式,即没有在ascii中[32, 126]出现。

      可是字符只能书写[32, 126]之间的字符, 因此这种状况下须要定义一种新的转义, 为不增长转义元字符, 转义字符还为\,

      转义规则为 \x == y,  x in [32, 126], y in [0, 31] or 127

说明: 若是对[32, 126]之间的非3 和 6中使用字符进行转义,即应用规则(\x), 则获得仍是x, 符合转义规则。

总结以下图:

demo代码:

            console.log('---- \\x present x (x is printable character) ----');
            console.log('slash + slash='+"\\"); // \ is part of transfer encoding syntax
            console.log('slash + "='+"\""); // " is collision with string syntax double quotation, eg "xx" wrapped by "
            
            console.log('---- \\x present control character ----');
            console.log('slash + n='+"\n"); // \n present line break

            console.log('---- \\x equal x when x is not needed transfer concoding ----');
            console.log('slash + 8='+"\8"); // \8 == 8
            console.log('slash + o='+"\o"); // \o == o
            console.log('slash + :='+"\:"); // \: == :

 

JQuery执行顺序跟踪

通过分析JQuery源代码, $("")的调用次序

一、 $ === jQuery.fn.init

二、 走到 jQuery.fn.init 中  return ( context || rootjQuery ).find( selector );

三、 find == jQuery.find == Sizzle

四、Sizzle 调用 newContext.querySelectorAll( newSelector )

而 querySelectorAll 为 最新浏览器都实现的 选择器查询接口,

各个DOM上都实现了 此接口, 详情见 http://www.cnblogs.com/snandy/archive/2011/03/30/1999388.html

因此查看到这里, 说明jquery 和 sizzle 未对选择器作处理。彻底是 浏览器实现 的 querySelectorAll接口行为。

 

CSS Selector规则

W3C对选择器有一套规范:

http://www.w3.org/TR/css3-selectors/#selectors

其中有对 id选择器的说明, 可见选择器的中 : 为选择器的元字符, 即保留字符, 作伪类使用,其余状况不能与之冲突。

因此读到此处,看官明白 $("#a\\:b"); 为何要对冒号添加转义了吧!

对于此选择器 即 "#a\\:b"  因为其自己是js字符串, \\表示\, 那么这个字符串在内存中的存储为

能够猜想 querySelectorAll 的实现, 首先会同js对selector字符串 作解析, 首先分析 : 前面不带\ 的冒号, 将其先后内容拆分, 前面为 选择器主体部分, 后面为伪类部分,

而后对 前面主题部分, 执行js字符串转义解析, 相似eval接口执行行为 :

eval("var evalselector = '#a\\:b';")
console.log(evalselector); // output  #a:b

将 转义表写 还原为 

 

运行以下js:

console.log("#a:b")
console.log("#a\:b")
console.log(document.querySelectorAll("#a\\:b").length)
console.log("[id^='a:b']")
console.log(document.querySelectorAll("[id^='a:b']").length)

打印以下:

结论 :

一、冒号(:)属于js中不用转义的普通可见字符, "#a:b" === "#a\:b"

二、 "#a\\:b" 为避免css selector伪类标识符号冲突的解法, 通过 js字符串转义,须要两个反斜杠\, 最后在 querySelectorAll接口中,将\:转换为:

三、 对于id中含有冒号的状况, 可使用"[id^='a:b']"的表写方式, 这种不须要对冒号转义, 由于这种格式不存在冲突的可能。

建议 id可变的状况,都使用"[id^='a:b']"方式。

demo code

<html>
<head> 
        <script type="text/javascript" src="./jquery.js"></script>
        <style>

        </style>
</head> 
<body>
        <input type="text" value="ddd" id="a:b">
        <script>
            console.log('---- \\x present x (x is printable character) ----');
            console.log('slash + slash='+"\\"); // \ is part of transfer encoding syntax
            console.log('slash + "='+"\""); // " is collision with string syntax double quotation, eg "xx" wrapped by "
            
            console.log('---- \\x present control character ----');
            console.log('slash + n='+"\n"); // \n present line break

            console.log('---- \\x equal x when x is not needed transfer concoding ----');
            console.log('slash + 8='+"\8"); // \8 == 8
            console.log('slash + o='+"\o"); // \o == o
            console.log('slash + :='+"\:"); // \: == :


            console.log('#a+slash+slash+:b='+"#a\\:b"); // #a\\:b == #a\:b
            console.log('jquery length='+$("#a\\:b").length); // length == 1 with selector #a\\:b
            console.log('jquery length='+$("[id^='a:b']").length); // length == 1 with selector [id^='a:b']


            console.log("#a:b") //output #a:b
            console.log("#a\:b") //output #a:b
            console.log(document.querySelectorAll("#a\\:b").length)//output 1
            console.log("[id^='a:b']") //: do not need transfer coding
            console.log(document.querySelectorAll("[id^='a:b']").length) //output 1
        </script>
</body>
</html>
相关文章
相关标签/搜索