当前位置: 首页 > 图文教程 > 网络编程 > Javascript > javascript 事件加载与预加载

Javascript
JavaScript 序列化对象实现代码
替代window.event.srcElement效果的可兼容性的函数
div+css+js模拟tab切换效果 事件绑定 IE,firefox兼容
IE和Firefox下event事件杂谈
javascript option onclick事件ie解决方案 兼容ie,firefox
javascript demo 基本技巧
用js实现层随着内容大小动态渐变改变 推荐
JS 的应用开发初探(mootools)
JS 在数组插入字符的实现代码(可参考JavaScript splice() 方法)
JQuery Tips(4) 一些关于提高JQuery性能的Tips
jQuery 淡入淡出、展开收缩菜单实现代码
js控制div及网页相关属性的代码
javascript 翻页测试页(动态创建标签并自动翻页)
Js获取table当前tr行的值的代码
IE 上下滚动展示模仿Marquee机制
jQuery解决iframe高度自适应代码
jQuery 连续列表实现代码
利用jQuery的$.event.fix函数统一浏览器event事件处理
Javascript和Ajax中文乱码吐血版解决方案
js Firefox 加入收藏夹功能代码 兼容Firefox 和 IE

Javascript 中的 javascript 事件加载与预加载


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2010-01-10   浏览: 102 ::
收藏到网摘: n/a

本文对JavaScript事件加载进行了一些延伸思考。加载多个事件时,使用window.onload可能会导致一些不便,而通过侦听器等方法,则可以解决这些问题。

通常来说,window.onload就够用了,如果想加载多个事件,我们可以采取以下方式:

复制代码 代码如下:

window.onload = function(){
func1();
func2();
func3();
//更多加载事件………………
}

但如果由于某种特殊需要,我们不能合在一起写吗?如当前区域是面向管理员,后台生成页面时只有当用户是管理员,页面才生成这部分,而这部分也用到一些特殊的脚本,上面的方法就歇菜了!
复制代码 代码如下:

//后台代码
<script type="text/javascript">
window.onload = function(){
func1();
func2();
//加载普通用户用到的脚本……
}
</script>
<%# 以下脚本是为管理员准备的 %>
<% if @user.role == "manager" %>
window.onload = function(){
func1();
func2();
//加载机密脚本……
}
<% end %>

这种情况生成出来的页面拥有两个window.onload代码块,很显然,第二个覆盖掉第一个。这时,轮到loadEvent函数出场了。
复制代码 代码如下:

var loadEvent = function(fn) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = fn;
}else {
window.onload = function() {
oldonload();
fn();
}
}
}

它非常完美地解决了互相覆盖的问题,用法如下:
复制代码 代码如下:

loadEvent(func1);
loadEvent(func2);
loadEvent(func3);
//更多加载事件

但现实的问题总是如此出奇不意,也如此刁钻邪门。最近我想把所有的函数放到一个闭包中,以免除命名冲突之苦,比如那个有名的$的DOM选择器。JQuery,Prototype,mootool都用它做选择器的名字,共存成了个严重的问题。
复制代码 代码如下:

(function(){
if(!window.JS){
window['JS'] = {}
}
var onReady = function(fn){
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = fn;
}else {
window.onload = function() {
oldonload();
fn();
}
}
}
JS.onReady = onReady;
var $ = function(id){
return document.getElementById(id);
}
JS.$ = $;
})()


[Ctrl+A 全选 提示:你可先修改部分代码,再按运行]

不过像这个如此有名的函数其实还有一个缺陷,就是新加载的函数被放置于前一个加载函数的作用域之用,加载函数越多,其栈的层次越深,显然性能耗很大。不过像onclick,onload,onmouseout等这样函数,W3C把它们归属于DOM0的事件模型,好处是适用范围广,但签于其性能,于是又提出DOM1.0的事件模型与DOM2.0的事件模型,DOM2就是原微软的事件模型与原网景的事件模型的合璧,既能捕获又能冒泡,而且多绑定多类型事件而不会导致后者覆盖前者。于是人们总搞出了有名的addEvent函数出来,我们用addEvent来改造我们的事件加载。
复制代码 代码如下:

(function(){
if(!window.JS){
window['JS'] = {}
}
var addEvent = function( obj, type, fn ) {
if (obj.addEventListener)
obj.addEventListener( type, fn, false );
else if (obj.attachEvent) {
obj["e"+type+fn] = fn;
obj.attachEvent( "on"+type, function() {
obj["e"+type+fn]();
} );
}
};
var onReady = function(loadEvent,waitForImages) {
if(waitForImages) {
return addEvent(window, 'load', loadEvent);
}
}
JS.onReady = onReady;
var $ = function(id){
return document.getElementById(id);
}
JS.$ = $;
})()


[Ctrl+A 全选 提示:你可先修改部分代码,再按运行]

OK,没问题。上面的onReady函数有一个可选参数,用于是否待图片加载。我们知道JS引擎会在完成DOM树后才开始处理图片与音频等东西,但如果我们的页面严重依赖于脚本布局呢?!我们想尽快让页面呈现出大体形态,这就用到domReady了。我们在原基础上改进它。
复制代码 代码如下:

(function(){
if(!window.JS){
window['JS'] = {}
}
var addEvent = function( obj, type, fn ) {
if (obj.addEventListener)
obj.addEventListener( type, fn, false );
else if (obj.attachEvent) {
obj["e"+type+fn] = fn;
obj.attachEvent( "on"+type, function() {
obj["e"+type+fn]();
} );
}
};
var onReady = function(loadEvent,waitForImages) {
if(waitForImages) {
return addEvent(window, 'load', loadEvent);
}
var init = function() {
if (arguments.callee.done) return;
arguments.callee.done = true;
loadEvent.apply(document,arguments);
};
if(!+"\v1"){
(function(){
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( arguments.callee, 0 );
return;
}
init();
})();
}else{
document.addEventListener( "DOMContentLoaded", function(){
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
init();
}, false );
}
return true;
}
JS.onReady = onReady;
var $ = function(id){
return document.getElementById(id);
}
JS.$ = $;
})()

dom标准浏览器用DOMContentLoaded,这是非常正现的W3C论DOM方法,与FF的DOMMouseScroll 不一样,基本上所有非IE内核的浏览器最新版都支持它了。IE下我们可以通过侦听document. documentElement. doScroll()来判断DOM树是否完成,原理是IE下只有当DOM树构建完成后才能doScroll。但它还不是尽善尽美,它在IE下无法判定 iframe的内容是否加载完毕。我们继续改进它。
复制代码 代码如下:

(function(){
if(!window.JS){
window['JS'] = {}
}
var addEvent = function( obj, type, fn ) {
if (obj.addEventListener)
obj.addEventListener( type, fn, false );
else if (obj.attachEvent) {
obj["e"+type+fn] = fn;
obj.attachEvent( "on"+type, function() {
obj["e"+type+fn]();
} );
}
};
var onReady = function(loadEvent,waitForImages) {
if(waitForImages) {
return addEvent(window, 'load', loadEvent);
}
var init = function() {
if (arguments.callee.done) return;
arguments.callee.done = true;
loadEvent.apply(document,arguments);
};
if(!+"\v1"){
if(window.self == window.top){
(function(){
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( arguments.callee, 0 );
return;
}
init();
})();
}else{
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
init();
}
});
}
}else{
document.addEventListener( "DOMContentLoaded", function(){
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
init();
}, false );
}
return true;
}
JS.onReady = onReady;
var $ = function(id){
return document.getElementById(id);
}
JS.$ = $;
})()

我们简直是在重新实现jquery的$(document).ready(function(){ })!它功能非常强悍,配合利用闭包做成的命名空间,基本刀枪不入。而且它就只污染一个全局变量“JS”,可以与YUI媲美了(笑)。不过对于一般应用来说,我们用不着做到如此面面俱到。假如我们不需要对图片进行处理,页面也没有iframe,我们可以搞下面这个微缩版出来。
复制代码 代码如下:

(function(){
if(!window.JS){
window['JS'] = {}
}
var onReady = function(loadEvent) {
if(!+"\v1"){
(function(){
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( arguments.callee, 0 );
return;
}
loadEvent();
})();
}else{
document.addEventListener( "DOMContentLoaded", loadEvent, false );
}
}
JS.onReady = onReady;
var $ = function(id){
return document.getElementById(id);
}
JS.$ = $;
})()