这两天在看《编写可维护的javascript》这本书,今天将事件处理这一章节做个记录,
首先看一段代码:
1 <!DOCTYPE HTML> <html> 2 <head> 3 <meta charset="utf-8" /> 4 <title></title> 5 <style type="text/css"> 6 #test{ 7 width: 100px; 8 height: 100px; 9 background: red; 10 position: absolute; 11 } 12 </style> 13 </head> 14 <body> 15 <div id="test"></div> 16 <script> 17 function handleClick(event){ 18 var test = document.getElementById('test'); 19 test.style.left = event.clientX + 'px'; 20 test.style.top = event.clientY + 'px'; 21 test.className = 'reveal'; 22 } 23 var btn = document.getElementById('btn'); 24 document.addEventListener('click', handleClick); 25 </script> 26 </body> 27 </html>
这段代码中click是用户行为来触发的,用户触发后处理handleClick事件,代码看起来合情合理没有任何问题。用户点击的时候,dom移到特定的位置,可如果鼠标移到某个点的时候dom同样需要移动到特定点呢?这个时候这段代码就会出现问题,最好的办法是将应用逻辑(移动到特定点)从事件处理程序中拆分出来。
function handleClick(event){ moveDom(event); } function moveDom(event){ var test = document.getElementById('test'); test.style.left = event.clientX + 'px'; test.style.top = event.clientY + 'px'; test.className = 'reveal'; } var btn = document.getElementById('btn'); document.addEventListener('click', function(event){ handleClick(event); });
这段拆离了应用逻辑,不管用户触发的是click还是mouseover只需要我们都只需要调用 moveDom()即可,不再局限于用户的点击行为。做完这一步,再看下一步。
event对象代表事件的状态,包含了各种各样的与事件相关的信息。在这段代码中的event对象从click的匿名事件处理中传到handleClick再传到moveDom,共分发了4次,但实际上在我们的应用逻辑中只用到了event(clientX、clientY)两个属性。这有什么问题?首先event对象作为参数传入并不能明确告诉我们该应用中event对象的哪些属性是我们所需要的,其次,当我们想单独测试测试应用逻辑的时候,必须重新创建一个event对象并作为参数传入。因此,我们可以再修改一下代码:
function handleClick(event){[/backcolor] moveDom(event.clientX, event.clientY); } function moveDom(x, y){ var test = document.getElementById('test'); test.style.left = x + 'px'; test.style.top = y + 'px'; test.className = 'reveal'; } var btn = document.getElementById('btn'); document.addEventListener('click', function(event){ handleClick(event); }); [backcolor=inherit]moveDom(20, 30); //任何地方都可以不依赖event对象和用户行为进行功能测试
现在不管我们是点击还是移动鼠标还是什么我们都只需要直接调用moveDom()函数即可,甚至可以单独使用moveDom()函数移动dom,由此可以看出拆分应用逻辑代码与合理分发event事件对象(不仅是event对象作为参数传入,所有参数传入都应该直观透明)可以有效的解耦代码,提高代码的复用性以及使用场合。
这段代码还有很多地方可以完善,比如定义一个全局对象,将事件处理程序挂载到这个全局对象上,dom对象也作为参数传入,className写入配置数据里。。。。。之后再讲这些吧。