我的思考 -- jquery live 的实现
前阵子写代码的时候,遇到前面人留下的jquery . 一直不会jquery, 硬着头皮,上了. 发现里面有一个很有意思的 函数 live
jquery的 live 这一函数让我初始觉得很神奇.
比如
<div id="c">
<li>1</li>
<li>2</li>
<li>3</li>
</div>
我用 jquery 的live ,绑定了 c 下的 li , 给了每个 li 一个onclick.
这样. 就算我 增加一个 li ,新的li 也拥有 onclick 这个属性的. 多么美好的 函数, 他居然可以无视 dom 是否改变,仍然给他的子级绑定函数. 这样一来, 在很多开发上, 将不需要老是对一些对象进行重复的判断,绑定, 无疑将会大大的增加其效率. 那么,他是怎么去实现这个的? (不好意思,我还是没去看jquery的源码, 因为感觉自己的研究,会更深刻),我那几天一直 去想着追究 怎么去判断 dom 是否已经被改变. 恩, 也许他是判断 dom 已经改变, 然后才重新给dom 下的子级重新绑定. 尽管如此, 如果能够达到相应的功能,那样也不错了.
为此还找到了一些 DOMAttrModified
DOMNodeInserted
DOMNodeRemoved 这样的方式 判断 dom 是否改变.
但是, jquery 的live 有一个重要的特点. 也是这个方式最大的缺陷, 那就是, 判断是否改变,本来就是一个过程. 也就是, 他需要先判断一次 dom 是否已经改变, 然后才决定是否重新绑定方法或者事件. 而 jquery 的live 显然没有这个缺陷 . 就算是用源生的 js 直接把 dom 的子级给删除了, 然后再绑定. 也仍然是可行的. 仍然是具备的. 也就是说, 从一开始,我去判断dom是否改变然后再判断 是否给重新绑定事件这一条路,本身, 就走岔了.
既然那样的话,其实,我还可以直接绑定父对象,然后根据 srcElement || target 来断父对象的子对象, 完成这个判定的
代码如下
1 <!doctype html>
2 <html>
3 <head>
4 <title></title>
5 </head>
6 <body>
7 <div id="c" style="width:100px;height;20px;margin:10px 20px;border:1px red solid;">
8 <li>1</li>
9 <li>2</li>
10 </div>
11 <script type="text/javascript">
12 var d = document,c = d.getElementById("c");
13 c.onclick = function(event){
14 var evt = event || window.event, es = evt.target || evt.srcElement;
15 if(/li/gi.test(es.nodeName)){
16 alert("yes");
17 }
18 }
19 setTimeout(function(){
20 c.innerHTML = "";
21 setTimeout(function(){
22 d.getElementById("c").innerHTML = "<li>1</li><li>2</li>lor: #000000;">";
23
24 },2000);
25 },2000);
26 </script>
27 </body>
28 </html>
29
这样看来 完全是可以实现了吧. 就算修改他的子级操作, 这样也是可行的了. 不管怎么样, 这样是可以实现的.
可是 javascript设计模式2 群里 的 番茄 , 还不死心, 他说,如果删除了 父级, 然后在重新建立一个和原来一样的父级和子级 , 那我刚刚的想法, 就失去功能拉. 而live 却是可以实现的.
真的是这样的吗?
然后我想到了用直接绑定, 给 c (依然是上面的例子) 直接绑定, 我做了下面的实现
<!doctype html>
<html>
<head>
<title></title>
</head>
<body>
<div id="c" style="width:100px;height;20px;margin:10px 20px;border:1px red solid;">a</div>
<script type="text/javascript">
var d = document,c = d.getElementById("c");
c.onclick = function(){
alert("yes");
}
setTimeout(function(){
d.body.removeChild(c);
setTimeout(function(){
var c = d.createElement("div");
c.id = "c",c.style.cssText = "width:100px;height;20px;margin:10px 20px;border:1px red solid;",
c.innerHTML = "a",
d.body.appendChild(c);
},2000);
},2000);
</script>
</body>
</html>
很显然, 他失败了. 再次点击的时候, 他已经失去了那个功能,那怕是使用 attachEvent 和 addEventListener .也无济于事的.
很显然, 这样的处理也是不厚道的. 那么,既然是这样的话,我能否给绑定到这个 对象的 父级 上去. 或者说是 总的父 级上去. document . 我来根据 document 来判断这个,这样总可以了吧, 就象上面根据 父级来判断子级一样的
我给出了下面的测试方式
1 <!doctype html>
2 <html>
3 <head>
4 <title></title>
5 </head>
6 <body>
7 <div id="c" style="width:100px;height;20px;margin:10px 20px;border:1px red solid;">a</div>
8 <script type="text/javascript">
9 var d = document,addEventHandler = [,].length == 2 ? function(element,evtName, callback){
10 element.attachEvent('on' + evtName, callback) ;
11 } : function(element,evtName, callback,useCapture){
12 element.addEventListener(evtName, callback,useCapture);
13 }
14 addEventHandler(document,"click",function(event){
15 var evt = event || window.event,c = evt.target || evt.srcElement;
16 if(c.id == "c"){
17 alert("yes");
18 }
19 },false);
20 setTimeout(function(){
21 d.body.removeChild(document.getElementById("c"));
22 setTimeout(function(){
23 var div = d.createElement("div");
24 div.id = "c";
25 div.style.cssText = "width:100px;height;20px;margin:10px 20px;border:1px red solid;"
26 div.innerHTML = "a";
27 d.body.appendChild(div);
28 },2000);
29 },3000);
30 </script>
31 </body>
32 </html>
33