使用clickCatcher在JS文件加载完毕/事件应用之前捕获Click事件
副标题[/!--empirenews.page--]
提高网站性能的方法之一就是将JavaScript文件放到文档的底部(我在Improve Your Web Site Performance – Tips & Tricks To Get A Good YSlow Rating中讨论过)。但是,这有一个缺点。 问题 在JavaScript文件加载完毕运行之前,你打算为文档中一些元素分配一个事件处理器。如果用户此时单击这些元素,会发生什么情况?那么浏览器将执行元素默认的行为。如,一个将用户带到另外一个页面的链接,而你并不打算这么做,而是想通过AJAX或其他方式动态加载一些信息。 理论解决方案 最近,我和我的同事David Billskog讨论并研究了这个问题,其解决方案是在文档的头部包含一个JavaScript块(inline或included),并确信能捕获页面中所有的click事件。然后过滤它们确定一个元素正是你正打算应用事件处理器的那个元素。 最后,当页面加载完毕/事件处理器已经分配时,移除先前分配的clickCatcher,迭代在这之前被点击的所有元素,然后触发这些元素真正的click事件,引发正常的和应用的事件行为。 实际解决方案 我和David开始各自的工作,对我来说,解决方案不需要任何JavaScript库,而David的解决方案是基于jQuery版本的(可以很容易的应用到任何其它库中)。我列出我的解决方案——clickCatcher。 clickCatcher使用一些简单的script函数作为基础:
The clickCatcher (function () { clickCatcher = function () { var clicks = [], addClicks = function (evt) { var classCheck = /catch/, body = /body/i, target = (evt.target)? evt.target : evt.srcElement; while (!classCheck.test(target.className) && !body.test(target.nodeName)) { target = target.parentNode; } if (classCheck.test(target.className)) { clicks.push(target); if (evt.preventDefault) { evt.preventDefault(); } evt.returnValue = false; return false; } }, callClicks = function () { removeEvent(document, "click", addClicks); for (var i=0, il=clicks.length; i<il; i++) { fireEvent(clicks[i], "click"); }; }, init = function () { addEvent(document, "click", addClicks); // Could be called here, but now called manually in script loaded later - adapt to your situation //addEvent(window, "load", callClicks); }; return { init : init, callClicks : callClicks }; }(); clickCatcher.init(); return clickCatcher; })(); clickCatcher封装在一个匿名的自调用函数之中,这样就不会与网页的全局变量相混淆,而是创建自己的作用域。如果你想在其它地方访问它,这部分代码可以选择性的暴露clickCatcher对象自身。代码给文档附加一个事件处理器,如果被单击的元素(或任何它的父元素)有类名catch(如链接),就将每一个click存储到一个数组中。 一旦页面加载完毕,你可以让其自动调用,或你可以通过调用clickCatcher.callClicks()方法手动触发它; 包含addEvent, removeEvent, fireEvent方法完整的代码,看起来就是这样: // By Robert Nyman, http://robertnyman.com/clickcatcher/ - This content is released under the MIT License: http://www.opensource.org/licenses/mit-license.php (function () { // addEvent by John Resig, http://ejohn.org/blog/flexible-javascript-events/ function addEvent( obj, type, fn ) { if ( obj.attachEvent ) { obj['e'+type+fn] = fn; obj[type+fn] = function(){obj['e'+type+fn]( window.event );} obj.attachEvent( 'on'+type, obj[type+fn] ); } else obj.addEventListener( type, fn, false ); } function removeEvent( obj, type, fn ) { if ( obj.detachEvent ) { obj.detachEvent( 'on'+type, obj[type+fn] ); obj[type+fn] = null; } else obj.removeEventListener( type, fn, false ); } // fireEvent by Jehiah Czebotar, http://jehiah.cz/archive/firing-javascript-events-properly function fireEvent(element, event) { var evt; if (document.createEvent) { // dispatch for firefox + others evt = document.createEvent("HTMLEvents"); evt.initEvent(event, true, true ); // event type,bubbling,cancelable return !element.dispatchEvent(evt); } else { // dispatch for IE evt = document.createEventObject(); return element.fireEvent('on'+event,evt); } } clickCatcher = function () { var clicks = [], addClicks = function (evt) { var classCheck = /catch/, body = /body/i, target = (evt.target)? evt.target : evt.srcElement; while (!classCheck.test(target.className) && !body.test(target.nodeName)) { target = target.parentNode; } if (classCheck.test(target.className)) { clicks.push(target); if (evt.preventDefault) { evt.preventDefault(); } evt.returnValue = false; return false; } }, callClicks = function () { removeEvent(document, "click", addClicks); for (var i=0, il=clicks.length; i<il; i++) { fireEvent(clicks[i], "click"); }; }, init = function () { addEvent(document, "click", addClicks); // Could be called here, but now called manually in script loaded later - adapt to your situation //addEvent(window, "load", callClicks); }; return { init : init, callClicks : callClicks }; }(); clickCatcher.init(); return clickCatcher; })(); 你可以到clickCatcher页测试这些代码。 setTimeout 技巧 (编辑:武汉站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |