在编程中,若是咱们不想或不可以直接操纵目标对象,咱们能够利用delegate建立一个代理对象来调用目标对象的方法,从而达到操纵目标对象的目的。毋庸置疑,代理对象要拥有目标对象的引用。咱们来看一下javascript的一个最简单实现:javascript
var delegate = function (client,clientMethod ){ |
return function () { return clientMethod.apply(client,arguments); } |
var agentMethod = delegate(client, client.method ) |
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<script type="text/javascript">
var ClassA = function(){
var _color = "red";
return {
getColor : function(){
document.write("<p>ClassA的实例的私有属性_color目前是<span style='color:"+_color+"' >"+_color+"</span></p>");
},
setColor:function(color){
_color = color;
}
};
};
var delegate = function (client,clientMethod ){
return function() { return clientMethod.apply(client,arguments); }
}
window.onload = function(){
var a = new ClassA();
a.getColor();
a.setColor("green");
a.getColor();
//alert(a._color);
document.write("<p>执行代理!</p>")
var d = delegate(a,a.setColor);
d("blue");
document.write("<p>执行完毕!</p>")
a.getColor();
};
</script>
<title>delegate</title>
</head>
<body>
</body>
</html>
或者咱们改变一下第二个参数,传个字符串进去:php
var delegate = function (client,clientMethod ){ |
return function () { return client[clientMethod].apply(client,arguments); } |
var d = delegate(a, "setColor" ); |
咱们还能够搞一些很好玩的东西,下面的例子取自一个日本博客。css
<script type="text/javascript">
Function.prototype.delegate = function(delegateFor){
return delegateFor.apply(null, arguments);
};
var Hoge = function(){
this.open = function (){
return 'this is Hoge#open';
};
this.close = function (){
return 'this is Hoge#close';
};
};
var Foo = function (){
this.name = 'foo';
this.open = function (){
return 'this is Foo#open';
};
this.close = function (){
return 'this is Foo#close';
};
};
var hoge = new Hoge;
var foo = new Foo;
alert(hoge.open()); // this is Hoge#open
alert(hoge.open.delegate(foo.open)); // this is Foo#open
alert(foo.open.delegate(hoge.open)); // this is Hoge#open
</script>
因为delegate实现目标对象的隐藏,这对于咱们保护一些核心对象是很是有用的。不过,说实在javascript的delegate基本算是call与apply的傀儡,由于js中只有这2个方法提供了改变当前函数内部this做用域的功能。不过,要实现对类的委托而不是实例的委托,这就复杂得多。Prototype.js,YUI与JQuery都有相应的实现。具体本身可去参考它们的源码。接着下来,我将讲述delegate在事件上的应用,这但是个无以伦比的东东,就是改变侦听器的位置(改变事件的绑定对象)。或者说,它得益于javascript独特的事件传播机制,所以实现起来很是容易,你们要好好运行它,我之前也在富文本编辑器中用过。html
$.addEvent(colorPicker, 'click' , function (){ |
var e = arguments[0] || window.event, |
td = e.srcElement ? e.srcElement : e.target, |
nn = td.nodeName.toLowerCase(); |
var cmd = colorPicker.getAttribute( "title" ); |
colorPicker.style.display = 'none' ; |
上面就是我在富文本编辑器撷取前景色与背景色的代码,注意,我是把事件绑定在颜色面板上,而不是面板上的那一个个格子上。为了直观起见,便于你们操做,我改用下面这个例子:java
如今咱们要点击列表中连接,取出里面的内容,传统的方法,咱们须要遍历添加全部a元素:node
window.onload = function (){ |
var nav = document.getElementById( "nav" ); |
var links = nav.getElementsByTagName( "a" ); |
for ( var i=0,l = links.length; i<l; i++) { |
links[i].onclick = function () { |
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<style type="text/css">
body{background:#fff;}
a { color:#8080C0;text-decoration:none;border-bottom:2px solid #fff;}
a:hover {color:#336699;border-bottom-color:#B45B3E;}
</style>
<script type="text/javascript">
window.onload = function(){
var nav = document.getElementById("nav");
var links = nav.getElementsByTagName("a");
for (var i=0,l = links.length; i <l; i++) {
links[i].onclick = function () {
alert(this.innerHTML);
return false;
}
}
}
</script>
<title>delegate</title>
</head>
<body>
<ul id="nav">
<li><a href="http://www.cnblogs.com/">博客园</a></li>
<li><a href="http://www.w3school.com.cn/">W3School</a></li>
<li><a href="http://study.163.com/">网易云课堂</a></li>
<li><a href="http://www.willspace.cn/">WILLSpace</a></li>
<li><a href="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
</ul>
</body>
</html>
新的方法,用nav代理了它下面全部元素,让它负责你们的onclick事件,包括它本身的,也无论是否为a元素,因此有时咱们须要作一些判断,但少了遍历DOM树,效率明显提升。jquery
window.onload = function (){ |
var nav = document.getElementById( "nav" ); |
nav.onclick = function () { |
var e = arguments[0] || window.event, |
target = e.srcElement ? e.srcElement : e.target; |
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<style type="text/css">
body{background:#fff;}
a { color:#8080C0;text-decoration:none;border-bottom:2px solid #fff;}
a:hover {color:#336699;border-bottom-color:#B45B3E;}
</style>
<script type="text/javascript">
window.onload = function(){
var nav = document.getElementById("nav");
nav.onclick = function () {
var e = arguments[0] || window.event,
target = e.srcElement ? e.srcElement : e.target;
alert(target.innerHTML);
return false;
}
}
</script>
<title>delegate</title>
</head>
<body>
<ul id="nav">
<li><a href="http://www.cnblogs.com/">博客园</a></li>
<li><a href="http://www.w3school.com.cn/">W3School</a></li>
<li><a href="http://study.163.com/">网易云课堂</a></li>
<li><a href="http://www.willspace.cn/">WILLSpace</a></li>
<li><a href="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
</ul>
</body>
</html>
为何它会行得通呢?!由于DOM2.0的事件模型是这样的,若是某个元素触发一个事件,如onclick,顶层对象document就会发出一个事件流,随着DOM树往目标元素流去,这就是传说中的捕获阶段,也就是原Netscape的事件执行模式,沿途的元素若是绑定了事件,它是不会执行的!第二阶段,就是到达了目标元素,执行它上面的绑定事件,但若是onclick只是个空实现,固然是没有效果啦!第三阶级,就是起泡阶级,原IE的事件执行模式,从目标元素往顶层元素折回,若是沿途有onclick事件,就随个触发!所以咱们是点击了a元素,但它的onclick事件为空,当事件流上浮到ul元素时,发现ul元素绑定了onclick事件,就执行当中的函数。若是ul的祖先元素也绑定了onclick事件呢?!继续执行!有多少执行多少!看下面的例子:web
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<style type="text/css">
body{background:#fff;}
a { color:#8080C0;text-decoration:none;border-bottom:2px solid #fff;}
a:hover {color:#336699;border-bottom-color:#B45B3E;}
</style>
<script type="text/javascript">
var addEvent = (function () {
if (document.addEventListener) {
return function (el, type, fn) {
el.addEventListener(type, fn, false);
};
} else {
return function (el, type, fn) {
el.attachEvent('on' + type, function () {
return fn.call(el, window.event);
});
}
}
})();
window.onload = function(){
var nav = document.getElementById("nav");
nav.onclick = function () {
var e = arguments[0] || window.event,
target = e.srcElement ? e.srcElement : e.target;
alert(target.innerHTML);
return false;
}
var wrapper = document.getElementById("wrapper");
addEvent(wrapper,'click',function(){
alert("冒泡过程连我也惊动了!");
});
}
</script>
<title>delegate</title>
</head>
<body>
<div id="wrapper">
<ul id="nav">
<li><a href="http://www.cnblogs.com/">博客园</a></li>
<li><a href="http://www.w3school.com.cn/">W3School</a></li>
<li><a href="http://study.163.com/">网易云课堂</a></li>
<li><a href="http://www.willspace.cn/">WILLSpace</a></li>
<li><a href="http://blog.csdn.net/willspace/">CSDN_WILLSpace</a></li>
</ul>
</div>
</body>
</html>
正因为这个特性,咱们就能够利用ul的onclick去代理它下面全部元素的onclick事件。原来,咱们须要给这些a元素准备五个侦听器(EventListener),如今咱们只须要1个,节省了4个,若是这个列表有一百行呢?就节省了99个!在商务应用,咱们通过会遇到许多报表(grid,实质是用table作的),咱们须要为每行添加悬浮变色效果与点击编辑功能,这就用到onmouseover 、 onmouseout 与 onclick事件,若是这个报表有五千行,咱们也只须要三个侦听器,节省了14997个!若是用传统方法作这个grid,IE6这样垃圾的游览器不卡到你吐血。所以,善用event delegation会大大提升咱们程序的性能。编程
附上一些有用的连接:ruby
文章转自: