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 = ;
  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 = ;
  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源码学习   dojo/dom模块作为一个基础模块,最常用的就是byId方法.除此之外还有isDescendant和setSelectable方法. dom.byId(myId)方法: ...

  2. dojo/dom-class源码学习

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

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

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

  4. 【iScroll源码学习04】分离IScroll核心

    前言 最近几天我们前前后后基本将iScroll源码学的七七八八了,文章中未涉及的各位就要自己去看了 1. [iScroll源码学习03]iScroll事件机制与滚动条的实现 2. [iScroll源码 ...

  5. 【iScroll源码学习03】iScroll事件机制与滚动条的实现

    前言 想不到又到周末了,周末的时间要抓紧学习才行,前几天我们学习了iScroll几点基础知识: 1. [iScroll源码学习02]分解iScroll三个核心事件点 2. [iScroll源码学习01 ...

  6. 【iScroll源码学习02】分解iScroll三个核心事件点

    前言 最近两天看到很多的总结性发言,我想想今年好像我的变化挺大的,是不是该晚上来水一发呢?嗯,决定了,晚上来水一发! 上周六,我们简单模拟了下iScroll的实现,周日我们开始了学习iScroll的源 ...

  7. 【iScroll源码学习00】模拟iScroll

    前言 相信对移动端有了解的朋友对iScroll这个库非常熟悉吧,今天我们就来说下我们移动页面的iScroll化 iScroll是我们必学框架之一,我们这次先根据iScroll功能自己实现其功能,然后再 ...

  8. 【iScroll源码学习01】准备阶段 - 叶小钗

    [iScroll源码学习01]准备阶段 - 叶小钗 时间 2013-12-29 18:41:00 博客园-原创精华区 原文  http://www.cnblogs.com/yexiaochai/p/3 ...

  9. 【 js 基础 】【 源码学习 】源码设计 (持续更新)

    学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...

随机推荐

  1. 我所理解的SoC

    前阵子出去找工作,有的人不太理解,你们SoC有什么可做的,不就是找几个IP来搭积木嘛.你那个FPGA prototyping有什么可做的,不就是编一个镜像嘛. 正好,新项目,重新开始做一颗SoC.接下 ...

  2. survey on Time Series Analysis Lib

    (1)I spent my 4th year Computing project on implementing time series forecasting for Java heap usage ...

  3. AngularJS之ng-options的best practise

    废话不多说,直接上代码. function MySelectCtrl($scope) { $scope.Model = [ { id: 10002, MainCategory: '男', Produc ...

  4. Android软件设计---Dumpsys工具使用

    Android中提供的dumpsys工具,用于分析Android性能.Android系统中,列出所有可用的dumpsys指令. 使用dumpsys查看memory信息: shell@aeon6735m ...

  5. Qt ffmpeg环境搭建

    ffmpeg下载地址:https://ffmpeg.zeranoe.com/builds/ 版本选择第一个,然后多少位看自己的pc(我的是64),右边对应三个都要下载,Static,Shared,De ...

  6. AngularJS学习总结

    第一章  简单认识AngularJS 1.双向数据绑定 可通过ng-model监控输入 ng-app属性声明所有被其包含的内容都属于这个AngularJs应用,这也是我们在web应用中嵌套Angula ...

  7. Java 下的 JSON库性能比较:JSON.simple

    JSON已经成为当前服务器与WEB应用之间数据传输的公认标准,不过正如许多我们所习以为常的事情一样,你会觉得这是理所当然的便不再深入思考了.我们很少会去想用到的这些JSON库到底有什么不同,但事实上它 ...

  8. linux进程间通信-共享内存

    转载:http://www.cnblogs.com/fangshenghui/p/4039720.html 一 共享内存介绍 共享内存可以从字面上去理解,就把一片逻辑内存共享出来,让不同的进程去访问它 ...

  9. ES5 getter setter

    最近在学习vuejs,了解到内部实现使用到了es5的Getters和Setters.之前看高程的时候,没有重视这块,今天查看一下文档,了解了他们的作用,再次记录一下,可供以后查看和共享. 定义Gett ...

  10. Java中将0x开头的十六进制字符串转换成十进制整数

    1.Integer.toString(int i) 由于input(输入数据)是以0x开头的字符串,并不是整型.因而在用 String s = Integer.toString(input); 时用会 ...