6-5 querySelector的兼容处理
本节编程练习不计算学习进度,请电脑登录imooc.com操作

querySelector的兼容处理

上一小节提到了querySelectorAll提供一个上下文范围,但是浏览器无视了这个上下文,默认还是类似document的处理。

那么针对这种情况如何兼容?

Andrew Dupont提出了一个解决方案,原理很简单:

context.querySelector
在上下文调用的context元素上指定一个id,通过这个限制范围,这个方法用的非常广泛。

我们看来自jQuery2.1.1的代码:

先看看jQuery最终的实现context.querySelectorAll用的上下文调用:

$('#test2').click(function() {
 //代码右图
}

代码可见newContext可能是document || 提供的一个上下文。

如: var context = document.querySelector('.aaron'); 此时的上下文即是<div class= "aaron">节点。

context.querySelectorAll('.aaron span') 在文档内找全部符合选择器描述的节点不包括Element本身。

最关键的地方其实就是通过给<div class= "aaron">加一个id用来限制范围,所以处理就变成了:

<div class= "aaron" id="[id='sizzle-1405486760710']">
context.querySelectorAll('[id='sizzle-1405486760710'] .aaron span')

注意finally总是执行context.removeAttribute("id"),意味着我们在之前的处理强制加了一个id,反推hack的手法,selectors前面指定上下文的的id,限制匹配的范围。

所以整个处理方式,我们可以总结几点:

1. 关键是给context设置一个id,所以上下文content,就会存在这个id限制范围。

2. 拼接出查询的选择器,附上这个ID前缀

newSelector: "[id='sizzle-1405486760710'] div[class='text']"

3. 查询

newContext.querySelectorAll( newSelector )

4. 因为强制加了ID,所以需要删除

context.removeAttribute("id");

这样就达到目的范围限制context.querySelectorAll了。

querySelectorAll在选择器上存在的问题,具体我是看jQuery的源码相关处理,基本都是IE8上的问题。jQuery对兼容的判断,都是采用的功能判断直接特性检测,伪造一个真实的环境测试支持度,针对querySelectorAll选取存在的问题之后分析。

任务

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <script src="http://code.jquery.com/jquery-latest.js"></script>
  6. <title></title>
  7. </head>
  8. <body>
  9.  
  10. <button id="test1">jQuery的querySelectorAll的处理</button>
  11. <button id="test2">模拟jQuery的querySelectorAll的处理</button>
  12.  
  13. <div class= "aaron">
  14. <p><span>慕课网</span></p>
  15. <div class="text">Aaron</div>
  16. </div>
  17.  
  18. <script type="text/javascript">
  19.  
  20.  
  21. $('#test1').click(function() {
  22. var a = $(".aaron");
  23. alert(a.find('.aaron span').length)
  24. })
  25.  
  26.  
  27. $('#test2').click(function() {
  28. var context = document.querySelector('.aaron');
  29. var old;
  30. var nid = Math.random();
  31.  
  32. //是否有ID/'|\\/g
  33. if ((old = context.getAttribute("id"))) {
  34. nid = old.replace(/'|\\/g, "\\$&");
  35. } else {
  36. context.setAttribute("id", nid);
  37. }
  38. nid = "[id='" + nid + "'] ";
  39.  
  40. var newSelector = nid + '.aaron span';
  41.  
  42. if (newSelector) {
  43. try {
  44. alert(context.querySelectorAll(newSelector).length)
  45. } catch (qsaError) {} finally {
  46. //如果是通过增加的范围,则要删除
  47. if (!old) {
  48. context.removeAttribute("id");
  49. }
  50. }
  51. }
  52. })
  53.  
  54.  
  55.  
  56.  
  57.  
  58. </script>
  59.  
  60. </body>
  61. </html>
下一节