很多时候,我们都会出现这样的困境:给DOM元素声明事件处理程序代码写在外部的一个js文件里,加载页面的时候,在js文件加载下来之前,用户操作的时候,事件程序都不会触发;特别是把事件处理函数写在了HTML标签里的时候,还会出现未定义的错误;还会带来一个点击按钮没有触发事件而导致可用性的问题。从这些情况出发,Robert写了一个叫ClickCatcher的对象,当相关的js文件还未加载下来的时候,用来缓存页面中的点击事件,等js文件加载下来之后,就执行缓存中的事件。下面是Robert写的ClickCatcher对象,我对它做了详细的注释:
[javascript]
"use strict"; //Don’t cancel
// By Robert Nyman, http://robertnyman.com/clickcatcher/ – This content is released under the (Link Goes Here) MIT
//License: http://www.opensource.org/licenses/mit-license.php
//url:http://robertnyman.com/2010/05/24/catching-clicks-with-clickcatcher-before-your-javascript-files-have-loadedevents-been-applied/
(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
//用于触发DOM元素已经声明的程序,类似于如:
/*
*document.onclick=function(){ alert("click"); }
*document.onclick();
*/
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;
//如果当前target元素没有包含class为catch的时候,就循环检查它的parentNode并且target不能是body元素
while (!classCheck.test(target.className) && !body.test(target.nodeName)) {
target = target.parentNode;
}
//如果还有指定class类的元素,就添加到clicks数组里缓存起来,并阻止浏览器的默认行为
if (classCheck.test(target.className)) {
clicks.push(target);
if (evt.preventDefault) {
evt.preventDefault();
}
evt.returnValue = false;
return false;
}
},
callClicks = function () {
//删除document的click事件
removeEvent(document, "click", addClicks);
//触发缓存中的全部事件
for (var i=0, il=clicks.length; i<il; i++) {
fireEvent(clicks[i], "click");
};
},
init = function () {
//给document添加click事件,用来实现事件委托,
addEvent(document, "click", addClicks);
};
return {
init : init,
callClicks : callClicks
};
}();
//初始化document的click事件,用来收集事件
clickCatcher.init();
return clickCatcher;
})();
[/javascript]
如上面代码所示,在初始化clickCatcher对象的时候,先给document添加click事件来收集页面中那些指定有class类的元素被点击了,这样在js文件加载完毕的时候可以按照顺序执行了,下面的Robert所提供的一个js外部文件的代码,并提供了一个示例页面《clickCatcher》:
[javascript]
//Page-specific script in this demo (in the clicks.js file)
var scriptLoaded = document.getElementById("script-loaded"),
imageLink = document.getElementById("image-link");
// Shows when the script is loaded
scriptLoaded.innerHTML = "true";
scriptLoaded.className = "loaded";
// Assigns click event to it
imageLink.onclick = function () {
if (confirm("Sure you want to go to the image page?")) {
location.href = imageLink.href;
}
return false;
};
// Call callClicks of clickCatcher,这句用于执行缓存中的全部click事件
clickCatcher.callClicks();
[/javascript]
上面的clickCatcher对象的解决方案,虽然能解决了文章开头所提到的几个问题,但是它还不够灵活,存在几个比较明显的问题:
- 页面中需要把clickCatcher对象的声明代码通过行内脚本的形式写在页面里,如果放到外部js文件中,还是会遇到开头所例举的几个问题;
- 当然这还遇到其他一些情况下的问题,就是在涉及用户同时点击了同一个标签元素的时候,事件缓存的次数就越多,这样有可能会导致一些可用性问题,特别是类似于一些显示隐藏类型的操作等等;
- 还有就是与外联的js文件存在依赖性,需要把执行缓存中的方法写在js文件里。
但是这种解决方案还是可以用于许多具体应用中的,比如:
- 导航工具栏,如果涉及到ajax调用数据的,普遍的做法是通过图示的做法表示应用在等待反应,这也是一种解决办法,但是它所遇到的问题是:当js文件是外联的时候,在js文件加载下来之前,操作是无效的,得不到任何的反应。而当前通过缓存事件,可以在js文件加载下来之前对操作进行缓存。
- 动画效果中,类似于这种视觉效果比较明显的应用,操作事件的时候提示错误或者效果无效,都是很大的可用性问题。通过事件的缓存方案,虽然在宽带慢的情况下会造成一定的延迟,但是能比较好的处理错误的出现和效果无效的情况。但是这也有可能让用户认为你的代码在一直执行,而且执行缓慢。
- 对于一些通过ajax刷新局部页面的应用,也同样适用。
原文:《Catching Clicks With ClickCatcher Before Your JavaScript Files Have Loaded/Events Been Applied》
参考:《Flexible Javascript Events》,《Firing Javascript Events (like onchange)》
nice.
怎么备案中了
这几天提交了备案,空间商说把首页给暂时封了,备案有更大的保障,所以暂时首页不能访问,其他页面没有影响。
博主的空间真好,欢迎来我家做客\(^o^)/~
嗯,还不错,内容挺丰富的,努力~
真不错,博客做的很精致!
看来让所有文件并行加载,也会出现问题;如果不让js和其它文件并行加载吧,用户又觉得慢.哎..