dojo/dom源码
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){
// inline'd 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
do{
if(typeof style[name] !== "undefined"){
// Supported; return property name
return name;
}
}while(i-- && (name = prefixes[i] + "UserSelect"));
// Not supported if we didn't 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特性来控制选择性。
分享一条小经验:设置一个元素不可选中时,最好在能满足需求的最远祖先上设置,如果仅仅在一个元素上设置未必能够达到效果;比如:设置一个图片不可选中,但是祖先可以选中,用户可能会祖先选中时会变蓝,看起来好像图片依然能够被选中。
dojo/dom源码的更多相关文章
- dojo/dom源码学习
dojo/dom模块作为一个基础模块,最常用的就是byId方法.除此之外还有isDescendant和setSelectable方法. dom.byId(myId)方法: 各种前端类库都免不了与D ...
- dojo/query源码解析
dojo/query模块是dojo为开发者提供的dom查询接口.该模块的输出对象是一个使用css选择符来查询dom元素并返回NodeList对象的函数.同时,dojo/query模块也是一个插件,开发 ...
- React v16-alpha 从virtual dom 到 dom 源码简读
一.物料准备 1.克隆react源码, github 地址:https://github.com/facebook/react.git 2.安装gulp 3.在react源码根目录下: $npm in ...
- dojo/dom-class源码学习
dom-class模块是dojo中对于一个元素class特性的操作(特性与属性的区别),主要方法有: contains 判断元素是否包含某个css class add 为元素添加某个css class ...
- dojo/aspect源码解析
dojo/aspect模块是dojo框架中对于AOP的实现.关于AOP的详细解释请读者另行查看其它资料,这里简单复习一下AOP中的基本概念: 切面(Aspect):其实就是共有功能的实现.如日志切面. ...
- vue虚拟DOM源码学习-vnode的挂载和更新流程
代码如下: <div id="app"> {{someVar}} </div> <script type="text/javascript& ...
- dojo/io-query源码解析
该模块主要对url中的query部分进行处理,我们发送GET请求时,将参数直接放在URL中,经常碰到的需求就是把一个对象转化为query字符串放到url中去发送GET请求.io-query模块便提供了 ...
- 使用struts dojo ajax源码案例
我这里使用的jar 包struts2-dojo-plugin-2.2.1.1.jar ===========jsp======================= <%@ taglib prefi ...
- dojo Provider(script、xhr、iframe)源码解析
总体结构 dojo/request/script.dojo/request/xhr.dojo/request/iframe这三者是dojo提供的provider.dojo将内部的所有provider构 ...
随机推荐
- 设备Oracle当误差:环境不符合要求》》解决方法
一旦安装Oracle当我常常会遇到这样的问题.也没太在意,改了一下client\stage\cvu文件夹cvu_prereq.xml档(添加支持目前的操作系统信息)为了克服,我没有做笔记,但后来有同学 ...
- linux下Ftp环境的搭建
Ftp环境的搭建 1.ftp软件的安装 使用ssh远程连接linux系统,上传和下载一些文件,Ftp是不可少的 Ftp的安装很简单,远程登录系统后使用命令 yum list vsftpd 通过提示 ...
- ios01
http://code4app.com/ 0.全部Swift http://numbbbbb.gitbooks.io/-the-swift-programming-language-/content/ ...
- J2SE习题(2)
第四.五周练习题 1.a. Define a class called BlogEntry that could be used to store an entry for a Weblog. Th ...
- linux上安装配置vsftpd(转)
转自:http://www.webarch.org/category/linux生产环境是Centos5.6,由于需要提供ftp服务,就找了一款比较小巧的ftp服务器端软件,vsftpd(vsftpd ...
- 【原创】《算法导论》链表一章带星习题试解——附C语言实现
原题: 双向链表中,需要三个基本数据,一个携带具体数据,一个携带指向上一环节的prev指针,一个携带指向下一环节的next指针.请改写双向链表,仅用一个指针np实现双向链表的功能.定义np为next ...
- HTML5游戏开发实战--当心
1.WebSocket它是HTML5该标准的一部分.Web页面可以用它来连接到持久socketserver在.该接口提供一个浏览器和server与事件驱动的连接.这意味着client每次需要时不再se ...
- solr与.net课程(七)solr主从复制
既然solr是解决大量数据全文索引的方案,因为高并发的问题,我们就要考虑solr的负载均衡了,solr提供很easy的主从复制的配置方法,那么以下我们就来配置一下solr的主从复制 如果我们在192. ...
- poj 1466 Girls and Boys (最大独立集)
链接:poj 1466 题意:有n个学生,每一个学生都和一些人有关系,如今要你找出最大的人数.使得这些人之间没关系 思路:求最大独立集,最大独立集=点数-最大匹配数 分析:建图时应该是一边是男生的点, ...
- 虚拟机VM10连衣裙Mac OS X 10.9.3
最近WWDC终极大招释放--新的编程语言Swift(迅速),导致大波浪,渴望围观程序猿.当然,工欲善其事,其利润,因此,对于那些谁不Mac非常为难.可是,请放心.本文教你怎样在Windows下也能体验 ...