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特性节点:
var te = id document.getElementById(id) te (te.attributes.id.value == id || te.id == id)如果上帝为你关上了一扇门,他一定会为你打开另一扇门(好矫情,就行天无绝人之路嘛)。ie4开始提供了document.all,它是一个代表所有元素的集合。document.all[myId]返回id为myId的一个元素或者包含name为myId的一个类数组。我们可以循环判断其中的元素是否满足要求:
var eles = document.all[id]; if(!eles || eles.nodeName){ eles = [eles]; // if more than 1, choose first with the correct id var i = 0; while((te = eles[i++])){ if((te.attributes te.attributes.id te.attributes.id.value == id) || te.id == id){ return te; }所以,dojo/dom中的实现根据浏览器的不同,有不同的实现:
if(has("ie")){ dom.byId = function(id, doc){ if(typeof id != "string"){ return id; var _d = doc || win.doc, te = id _d.getElementById(id); // attributes.id.value is better than just id in case the // user has a name=id inside a form if(te (te.attributes.id.value == id || te.id == id)){ return te; }else{ var eles = _d.all[id]; if(!eles || eles.nodeName){ eles = [eles]; // if more than 1, choose first with the correct id var i = 0; while((te = eles[i++])){ if((te.attributes te.attributes.id te.attributes.id.value == id) || te.id == id){ return te; }else{ dom.byId = function(id, doc){ // inlined type check. // be sure to return null per documentation, to match IE branch. return ((typeof id == "string") ? (doc || win.doc).getElementById(id) : id) || null; // DOMNode }
dom.isDescendant(node, ancestor)方法:
这个方法用来判断node是否是ancestor的一个子节点,其实就是孩子找父亲。孩子找父亲比较简单,而父亲找孩子是比较难的,因为子节点一定有父节点,所以只要一级一级的找上去即可。
dom.isDescendant = function(/*DOMNode|String*/ node, /*DOMNode|String*/ ancestor){ try{ node = dom.byId(node); ancestor = dom.byId(ancestor); while(node){ if(node == ancestor){ return true; // Boolean node = node.parentNode; }catch(e){ /* squelch, return false */ } return false; // Boolean };其实还有一个原生的函数也可以满足要求:element.contains方法,不过这个方法并没有被纳入规范中。但是几乎所有的浏览器都支持,包括IE(最初就是ie增加的该方法,总算做了件好事。。)。所以该方法也可以这样实现:
dom.isDescendant = function(/*DOMNode|String*/ node, /*DOMNode|String*/ ancestor){ try{ node = dom.byId(node); ancestor = dom.byId(ancestor); return ancestor.contains(node); }catch(e){ /* squelch, return false */ } return false; // Boolean };
dom.setSelectable(node, selectable)方法:
看名字也知道是用来设置一个节点及其自己点是否可选中的。css属性中可以通过设置“user-select”来控制一个元素是否可选择,但这个属性并未被纳入标准中去,所以各个浏览器中都需要加浏览器前缀,如:-webkit、-moz、-ms、-o等;所以我们可以通过设置元素的style属性中的相应属性来控制元素的可选择性。但是,ie总是太操蛋,大多数情况下,ms前缀都可以解决问题,但是如果一个将一个frame作为编辑器使用时,设置msUserSelect为none时无法达到效果,所以在ie中我们利用unselectable特性来解决这个问题。ie下存在的这个特性:unselectable, 设为on则不可选中,移除这个属性则表示可选中。
dojo的实现中,首先判断userSelect属性是否能使用:
has.add("css-user-select", function(global, doc, element){ // Avoid exception when dom.js is loaded in non-browser environments if(!element){ return false; } var style = element.style; var prefixes = ["Khtml", "O", "Moz", "Webkit"], i = prefixes.length, name = "userSelect", prefix; // Iterate prefixes from most to least likely if(typeof style[name] !== "undefined"){ // Supported; return property name return name; }while(i-- (name = prefixes[i] + "UserSelect")); // Not supported if we didnt return before now return false; });
这里省略了ms前缀。
然后根据对"css-user-select"的支持,使用不同的实现:
var cssUserSelect = has("css-user-select"); dom.setSelectable = cssUserSelect ? function(node, selectable){ // css-user-select returns a (possibly vendor-prefixed) CSS property name dom.byId(node).style[cssUserSelect] = selectable ? "" : "none"; } : function(node, selectable){ node = dom.byId(node); // (IE 10 / Opera) Fall back to setting/removing the // unselectable attribute on the element and all its children var nodes = node.getElementsByTagName("*"), i = nodes.length; if(selectable){ node.removeAttribute("unselectable"); while(i--){ nodes[i].removeAttribute("unselectable"); }else{ node.setAttribute("unselectable", "on"); while(i--){ nodes[i].setAttribute("unselectable", "on"); };
ie中,循环改变所有子节点的unselectable特性来控制选择性。
分享一条小经验:设置一个元素不可选中时,最好在能满足需求的最远祖先上设置,如果仅仅在一个元素上设置未必能够达到效果;比如:设置一个图片不可选中,但是祖先可以选中,用户可能会祖先选中时会变蓝,看起来好像图片依然能够被选中。
如果您觉得这篇文章对您有帮助,请不吝点击下方的推荐按钮,您的鼓励是我分享的动力!
【前端】JQuery框架 -- JQuery怎么使用和各个版本的区别、JQuery对象和JS对象区别、JQuery选择器 JQuery框架 -- JQuery怎么使用和各个版本的区别、JQuery对象和JS对象区别、JQuery选择器? jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨 是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。
相关文章
- mybatis简单案例源码详细【注释全面】——实体层(User.java)
- 购物车的功能——界面源码
- Hadoop源码学习:RPC
- xgboost 源码学习
- MFC Windows 程序设计[316]之渐变色文档菜单自绘(附源码)
- MFC Windows 程序设计[187]之多样的按钮(附源码)
- Opencv学习笔记 OpenCV源码以及模块的组成结构
- Java多线程学习笔记 - 三、Thread类源码内的方法概览
- 不一样的视角来学习Spring源码之容器与Bean---上
- Android音视频开发学习路线+项目实战+源码解析(WebRTC Native 源码、X264源码、FFmpeg、Opus源码.....)
- 企业级Android音视频开发学习路线+项目实战+源码解析(WebRTC Native 源码、X264源码、FFmpeg、Opus源码.....)
- Redis源码学习——基础数据结构之SDS
- 【Python】采集3万张4K超清壁纸,实现定时自动更换桌面壁纸脚本(内含完整源码)
- 机器学习案例(六):Python 大数据进行信用卡欺诈检测(完整源码和分析)
- 一文讲尽Thread类的源码精髓
- 第二人生的源码分析(六十一)LLCurl类实现libcurl库封装
- JAVA虚拟机源码学习笔记之一
- (01)ORB-SLAM2源码无死角解析-(35) 跟踪线程→恒速模型跟踪当前普通帧TrackWithMotionModel()
- 题目:javaWeb药房药品管理系统(附源码链接免费下载)
- Python开发指南[1]之程序员计时小时钟(附源码)
- [YOLOv7]基于YOLOv7的反光衣检测系统(源码&部署教程&数据集)
- 【redis源码学习】redis 中的“消息队列” Stream
- 【redis源码学习】redis启动并读取配置文件的过程
- GreenPlum的学习心得和知识总结(一)|GreenPlum数据库源码编译安装及学习资料汇总
- libvirt零知识学习2 —— libvirt源码下载
- QEMU零知识学习2 —— QEMU源码下载