dojo/dom源码学习

 

  dojo/dom模块作为一个基础模块,最常用的就是byId方法。除此之外还有isDescendant和setSelectable方法。

  dom.byId(myId)方法:

    各种前端类库都免不了与DOM节点打交道,操作DOM的方法千变万化最终还是要回到原生的那几个方法中,因为类库再快也快不过原生。所以在dom.byId方法中,还是要依靠document.getElementById('myId')方法。假如没有ie,假如不要考虑兼容性,getElementById方法可以完全满足我们的需求。但是,ie毁了一切,借用美国同事的一句话:Fuck the stupid IE! 兼容性问题有两条:

  • ie8及较低版本中,myId不区分大小写,所以myid跟myId会返回同样的结果
  • ie7及较低版本中,如果name名称与给定ID相同的表单元素且表单元素在给定ID元素的前面,那么IE就会返回那个表单元素

  这就要求我们在必须判断一下得到的元素的id是否真与传入参数相同。判断方法是利用id属性或id特性节点:

  1. var te = id && document.getElementById(id)
  2. te && (te.attributes.id.value == id || te.id == id)

  如果上帝为你关上了一扇门,他一定会为你打开另一扇门(好矫情,就行天无绝人之路嘛)。ie4开始提供了document.all,它是一个代表所有元素的集合。document.all[myId]返回id为myId的一个元素或者包含name为myId的一个类数组。我们可以循环判断其中的元素是否满足要求:

  1. var eles = document.all[id];
  2. if(!eles || eles.nodeName){
  3. eles = [eles];
  4. }
  5. // if more than 1, choose first with the correct id
  6. var i = 0;
  7. while((te = eles[i++])){
  8. if((te.attributes && te.attributes.id && te.attributes.id.value == id) || te.id == id){
  9. return te;
  10. }
  11. }

  所以,dojo/dom中的实现根据浏览器的不同,有不同的实现:

  1. if(has("ie")){
  2. dom.byId = function(id, doc){
  3. if(typeof id != "string"){
  4. return id;
  5. }
  6. var _d = doc || win.doc, te = id && _d.getElementById(id);
  7. // attributes.id.value is better than just id in case the
  8. // user has a name=id inside a form
  9. if(te && (te.attributes.id.value == id || te.id == id)){
  10. return te;
  11. }else{
  12. var eles = _d.all[id];
  13. if(!eles || eles.nodeName){
  14. eles = [eles];
  15. }
  16. // if more than 1, choose first with the correct id
  17. var i = 0;
  18. while((te = eles[i++])){
  19. if((te.attributes && te.attributes.id && te.attributes.id.value == id) || te.id == id){
  20. return te;
  21. }
  22. }
  23. }
  24. };
  25. }else{
  26. dom.byId = function(id, doc){
  27. // inline'd type check.
  28. // be sure to return null per documentation, to match IE branch.
  29. return ((typeof id == "string") ? (doc || win.doc).getElementById(id) : id) || null; // DOMNode
  30. };
  31. }

  

  dom.isDescendant(node, ancestor)方法:

  这个方法用来判断node是否是ancestor的一个子节点,其实就是孩子找父亲。孩子找父亲比较简单,而父亲找孩子是比较难的,因为子节点一定有父节点,所以只要一级一级的找上去即可。

  1. dom.isDescendant = function(/*DOMNode|String*/ node, /*DOMNode|String*/ ancestor){
  2.  
  3. try{
  4. node = dom.byId(node);
  5. ancestor = dom.byId(ancestor);
  6. while(node){
  7. if(node == ancestor){
  8. return true; // Boolean
  9. }
  10. node = node.parentNode;
  11. }
  12. }catch(e){ /* squelch, return false */ }
  13. return false; // Boolean
  14. };

  其实还有一个原生的函数也可以满足要求:element.contains方法,不过这个方法并没有被纳入规范中。但是几乎所有的浏览器都支持,包括IE(最初就是ie增加的该方法,总算做了件好事。。)。所以该方法也可以这样实现:

  1. dom.isDescendant = function(/*DOMNode|String*/ node, /*DOMNode|String*/ ancestor){
  2. try{
  3. node = dom.byId(node);
  4. ancestor = dom.byId(ancestor);
  5. return ancestor.contains(node);
  6. }catch(e){ /* squelch, return false */ }
  7. return false; // Boolean
  8. };

  dom.setSelectable(node, selectable)方法:

  看名字也知道是用来设置一个节点及其自己点是否可选中的。css属性中可以通过设置“user-select”来控制一个元素是否可选择,但这个属性并未被纳入标准中去,所以各个浏览器中都需要加浏览器前缀,如:-webkit、-moz、-ms、-o等;所以我们可以通过设置元素的style属性中的相应属性来控制元素的可选择性。但是,ie总是太操蛋,大多数情况下,ms前缀都可以解决问题,但是如果一个将一个frame作为编辑器使用时,设置msUserSelect为none时无法达到效果,所以在ie中我们利用unselectable特性来解决这个问题。ie下存在的这个特性:unselectable, 设为on则不可选中,移除这个属性则表示可选中。

  dojo的实现中,首先判断userSelect属性是否能使用:

  1. has.add("css-user-select", function(global, doc, element){
  2. // Avoid exception when dom.js is loaded in non-browser environments
  3. if(!element){ return false; }
  4.  
  5. var style = element.style;
  6. var prefixes = ["Khtml", "O", "Moz", "Webkit"],
  7. i = prefixes.length,
  8. name = "userSelect",
  9. prefix;
  10.  
  11. // Iterate prefixes from most to least likely
  12. do{
  13. if(typeof style[name] !== "undefined"){
  14. // Supported; return property name
  15. return name;
  16. }
  17. }while(i-- && (name = prefixes[i] + "UserSelect"));
  18.  
  19. // Not supported if we didn't return before now
  20. return false;
  21. });

  这里省略了ms前缀。

  然后根据对"css-user-select"的支持,使用不同的实现:

  1. var cssUserSelect = has("css-user-select");
  2. dom.setSelectable = cssUserSelect ? function(node, selectable){
  3. // css-user-select returns a (possibly vendor-prefixed) CSS property name
  4. dom.byId(node).style[cssUserSelect] = selectable ? "" : "none";
  5. } : function(node, selectable){
  6. node = dom.byId(node);
  7.  
  8. // (IE < 10 / Opera) Fall back to setting/removing the
  9. // unselectable attribute on the element and all its children
  10. var nodes = node.getElementsByTagName("*"),
  11. i = nodes.length;
  12.  
  13. if(selectable){
  14. node.removeAttribute("unselectable");
  15. while(i--){
  16. nodes[i].removeAttribute("unselectable");
  17. }
  18. }else{
  19. node.setAttribute("unselectable", "on");
  20. while(i--){
  21. nodes[i].setAttribute("unselectable", "on");
  22. }
  23. }
  24. };

  ie中,循环改变所有子节点的unselectable特性来控制选择性。

  分享一条小经验:设置一个元素不可选中时,最好在能满足需求的最远祖先上设置,如果仅仅在一个元素上设置未必能够达到效果;比如:设置一个图片不可选中,但是祖先可以选中,用户可能会祖先选中时会变蓝,看起来好像图片依然能够被选中。

dojo/dom源码的更多相关文章

  1. dojo/dom源码学习

    dojo/dom模块作为一个基础模块,最常用的就是byId方法.除此之外还有isDescendant和setSelectable方法. dom.byId(myId)方法:   各种前端类库都免不了与D ...

  2. dojo/query源码解析

    dojo/query模块是dojo为开发者提供的dom查询接口.该模块的输出对象是一个使用css选择符来查询dom元素并返回NodeList对象的函数.同时,dojo/query模块也是一个插件,开发 ...

  3. React v16-alpha 从virtual dom 到 dom 源码简读

    一.物料准备 1.克隆react源码, github 地址:https://github.com/facebook/react.git 2.安装gulp 3.在react源码根目录下: $npm in ...

  4. dojo/dom-class源码学习

    dom-class模块是dojo中对于一个元素class特性的操作(特性与属性的区别),主要方法有: contains 判断元素是否包含某个css class add 为元素添加某个css class ...

  5. dojo/aspect源码解析

    dojo/aspect模块是dojo框架中对于AOP的实现.关于AOP的详细解释请读者另行查看其它资料,这里简单复习一下AOP中的基本概念: 切面(Aspect):其实就是共有功能的实现.如日志切面. ...

  6. vue虚拟DOM源码学习-vnode的挂载和更新流程

    代码如下: <div id="app"> {{someVar}} </div> <script type="text/javascript& ...

  7. dojo/io-query源码解析

    该模块主要对url中的query部分进行处理,我们发送GET请求时,将参数直接放在URL中,经常碰到的需求就是把一个对象转化为query字符串放到url中去发送GET请求.io-query模块便提供了 ...

  8. 使用struts dojo ajax源码案例

    我这里使用的jar 包struts2-dojo-plugin-2.2.1.1.jar ===========jsp======================= <%@ taglib prefi ...

  9. dojo Provider(script、xhr、iframe)源码解析

    总体结构 dojo/request/script.dojo/request/xhr.dojo/request/iframe这三者是dojo提供的provider.dojo将内部的所有provider构 ...

随机推荐

  1. ASP.NET之Cookie(坑爹的Response.Cookies.Remove)

    原文:ASP.NET之Cookie(坑爹的Response.Cookies.Remove) 在web开发中Cookie是必不可少的 .NET自然也有一个强大的Cookie操作类,我们用起来也非常方便, ...

  2. LVM逻辑卷管理@设备、格式、摩、引导自己主动安装一个完整的章节

    离http://www.it165.net/admin/html/201307/1553.html LVM的重要性,在这里我也就不多说了,今天和大家分享一下.LVM设备,而且安装方式. 首先呢,先让我 ...

  3. IIS6,IIS7中查看w3wp进程

    当我们服务器创建了很多应用程序池,然后某个w3wp.exe进程占用CPU和内存过高,我们怎么查找这个w3wp.exe进程属于哪一个网站呢.其实微软为我们提供了很好的查看工具: 首先打开windows任 ...

  4. shell文字过滤程序(十):cut命令

    [版权声明:转载请保留源:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] cut指挥类似至awk,从行内提取的信息,它是一个较弱的版本的功能 ...

  5. SCM文章10课时:定时器中断

    JP3遇见P0口. #include<reg51.h> #define uchar unsigned char uchar flag,num; uchar code smg[10] = { ...

  6. [LeetCode]Word Ladder 最短距离字符串转换 (Dijkstra)

    要求最短距离.采纳dijkstra查找节点之间的最短路径. 当心:假设是一个枚举字典22是否元素可以,如果转换,暂停. 提高:每串,带您历数它的字符值事件,对于的长度n一个字符串枚举n*26次要. 设 ...

  7. c# 获取某个对象的[公有属性]的名称,类型,值

    /// <summary> /// 获取某个对象的[公有属性]的名称,类型,值 /// </summary> /// <typeparam name="T&qu ...

  8. 【Linux】lvm基础操作

    新增两块硬盘,来进行实验: [root@jp ~]# fdisk -l Disk /dev/sda: 107.3 GB, 107374182400 bytes 255 heads, 63 sector ...

  9. android存储阵列数据SharedPreferences

    假设要数组数据(如boolean[] .int[]等)到SharedPreferences时,我们能够先将数组数据组织成json数据存储到SharedPreferences,读取时则对json数据进行 ...

  10. 宝更容易使用比读IC卡信息的工具

    编程语言:VC++ 更新时间:2014.10.23 操作系统:windowAll 工具:PCSC读卡器 在上一个博文<<解惑:NFC手机怎样轻松读取银行卡信息?>>中,介绍了支 ...