<input type="button" value="Click Me" onclick="try{showMessage();}catch(ex){}">

使用try catch捕获错误

        try {
            var dd = document.getElemedntById('dd')

        } catch (ex) {
            alert(123)
        }

addEventListener(),最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程

try {
    btn.addEventListener('click', function() {
        alert(this.id)
    }, false)
} catch (ex) {
    btn.attachEvent('onclick', function() {
        alert(123)
    })
}

removeEventListener(),要使用命名函数才能移除


btnfn = function() {
    alert(this.id)
}

btn.addEventListener('click', btnfn, false)

btn.removeEventListener('click',btnfn,false)

attachEvent()与detachEvent(),1、this作用域为window; 2、执行顺序由后往前;

btn.attachEvent('onclick',function(){
    alert(this)  //特别注意,这里是window
})

btn.attachEvent("onclick", function(){
alert("Clicked"); //弹2
});
btn.attachEvent("onclick", function(){
alert("Hello world!"); //弹1
});

兼容方法:

var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    }
};

var handler = function() {
    alert('abc')
}

EventUtil.addHandler(btn, 'click', handler)
EventUtil.removeHandler(btn, "click", handler);

事件对象

对象this 始终等于currentTarget 的值,而target 则只包含事件的实
际目标。如果直接将事件处理程序指定给了目标元素,则this、currentTarget 和target 包含相同
的值。来看下面的例子。

btn.onclick = function(event){
    alert(event.currentTarget === this)
    alert(event.target === this)
}
document.body.onclick = function(event) {
    alert(event.currentTarget == document.body) //true
    alert(this === document.body) //true
    alert(event.target == document.getElementById('mybtn')) //true
}

使用event.type判断不同事件;

var handler = function(event) {
    switch (event.type) {
        case 'click':
            alert('clicked')
            break;
        case 'mouseover':
            alert('mouseovered')
            break;
        case 'mouseout':
            alert('mouseouted');
            break;
    }
}
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
btn.onclick = function(event) {
    alert('clicked')
    event.stopPropagation()
}
document.body.onclick = function(event) {
    alert('body clicked')
}

IE下的事件;

所以不能认为this 会始终等于事件目标。故而,最好还是使用event.srcElement 比较保

var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(window.event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});

cancelBubble 属性与DOM 中的stopPropagation()方法作用相同,都是用来停止事
件冒泡的。由于IE 不支持事件捕获,因而只能取消事件冒泡;但stopPropagatioin()可以同时取消
事件捕获和冒泡

所以综合起来的跨浏览器事件代码为:


var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

//使用
btn.onclick = function(event) {
    event = EventUtil.getEvent(event);
};
btn.onclick = function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
};
var link = document.getElementById("myLink");
link.onclick = function(event) {
    event = EventUtil.getEvent(event);
    EventUtil.preventDefault(event);
};
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
    alert("Clicked");
    event = EventUtil.getEvent(event);
    EventUtil.stopPropagation(event);
};
document.body.onclick = function(event) {
    alert("Body clicked");
};

图片加载完后显示弹出

var image = document.getElementById('myimage')
EventUtil.addHandler(image,'load',function(event){
    event = EventUtil.getEvent(event);
    alert(EventUtil.getTarget(event).src);
})

EventUtil.addHandler(window,'load',function(){
    var image = new Image();
    EventUtil.addHandler(image,'load',function(event){
        alert('Image Loaded')
    })
    image.src = 'smail.gif'
})

script外部地址加载完成

EventUtil.addHandler(window,'load',function(){
 var _srcipt = document.createElement('script')
 EventUtil.addHandler(_srcipt,'load',function(event){
     alert('loaded')
 })
 _srcipt.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'
 document.body.appendChild(_srcipt)
})

css外部检测,低版本chrome/firefox可能不支持,未验证

EventUtil.addHandler(window, 'load', function() {
    var _css = document.createElement('link')
    _css.type = 'text/css'
    _css.rel = 'stylesheet'
    EventUtil.addHandler(_css, 'load', function(event) {
        alert('loaded')
    })
    _css.href = 'https://assets-cdn.github.com/assets/frameworks-827a4e004aa05724993ea7616e4af53894825443811a270e2b9bce76e3453f19.css'
    document.body.appendChild(_srcipt)
})

resize事件,推荐写法

EventUtil.addHandler(window, "resize", function(event) {
    alert("Resized");
});

EventUtil.addHandler(window, "scroll", function(event) {
    if (document.compatMode == "CSS1Compat") {
        alert(document.documentElement.scrollTop);
    } else {
        alert(document.body.scrollTop);
    }
});

焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及
document.activeElement 属性配合,可以知晓用户在页面上的行踪。有以下6 个焦点事件。

 blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
 DOMFocusIn:在元素获得焦点时触发。这个事件与HTML 事件focus 等价,但它冒泡。只有
Opera 支持这个事件。DOM3 级事件废弃了DOMFocusIn,选择了focusin。
 DOMFocusOut:在元素失去焦点时触发。这个事件是HTML 事件blur 的通用版本。只有Opera
支持这个事件。DOM3 级事件废弃了DOMFocusOut,选择了focusout。
focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
 focusin:在元素获得焦点时触发。这个事件与HTML 事件focus 等价,但它冒泡。支持这个
事件的浏览器有IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。
 focusout:在元素失去焦点时触发。这个事件是HTML 事件blur 的通用版本。支持这个事件
的浏览器有IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。

当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
(1) focusout 在失去焦点的元素上触发;
(2) focusin 在获得焦点的元素上触发;
(3) blur 在失去焦点的元素上触发;
(4) DOMFocusOut 在失去焦点的元素上触发;
(5) focus 在获得焦点的元素上触发;
(6) DOMFocusIn 在获得焦点的元素上触发。

事件都不冒泡

var _mybtn = document.getElementById('mybtn')

EventUtil.addHandler(_mybtn, 'focus', function() { //获得
    alert(1)
})
EventUtil.addHandler(_mybtn, 'blur', function() {//失去
    alert(2)
})
EventUtil.addHandler(_mybtn, 'focusin', function() {//获得
    alert(1)
})
EventUtil.addHandler(_mybtn, 'focusout', function() {//失去
    alert(2)
})

鼠标与滚轮事件

click/dblclick/mouseenter/mouseleave/mousemove/mouseout/mouseover/mouseup/

执行顺序:
(1) mousedown
(2) mouseup
(3) click
(4) mouseup
(5) dblclick
可以使用类似下列代码取得鼠标事件的客户端坐标信息:

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Client coordinates: " + event.clientX + "," + event.clientY);
});

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Page coordinates: " + event.pageX + "," + event.pageY);
});

在页面没有滚动的情况下,pageX 和pageY 的值与clientX 和clientY 的值相等。

滚动情况下:page 一定大于 client

EventUtil.addHandler(document.body, "click", function(event) {
    event = EventUtil.getEvent(event);
    console.log("Page coordinates: " + event.pageX + "," + event.pageY);
});

EventUtil.addHandler(document.body, "click", function(event) {
    event = EventUtil.getEvent(event);
    console.log("client coordinates: " + event.clientX + "," + event.clientY);
});

IE8不支持page,所以可用client + scroll 相加计算出

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
    event = EventUtil.getEvent(event);
    var pageX = event.pageX,
        pageY = event.pageY;
    if (pageX === undefined) {
        pageX = event.clientX + (document.body.scrollLeft ||
            document.documentElement.scrollLeft);
    }
    if (pageY === undefined) {
        pageY = event.clientY + (document.body.scrollTop ||
            document.documentElement.scrollTop);
    }
    alert("Page coordinates: " + pageX + "," + pageY);
});

鼠标相对于整个屏幕坐标位置,screenX 和 screenY

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Screen coordinates: " + event.screenX + "," + event.screenY);
});

虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要
采取的操作。这些修改键就是Shift、Ctrl、Alt 和Meta(在Windows 键盘中是Windows 键,在苹果机中
是Cmd 键),它们经常被用来修改鼠标事件的行为。DOM 为此规定了4 个属性,表示这些修改键的状
态:shiftKey、ctrlKey、altKey 和metaKey。这些属性中包含的都是布尔值,如果相应的键被按
下了,则值为true,否则值为false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户
是否同时按下了其中的键。来看下面的

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
    event = EventUtil.getEvent(event);
    var keys = new Array();
    if (event.shiftKey) {
        keys.push("shift");
    }
    if (event.ctrlKey) {
        keys.push("ctrl");
    }
    if (event.altKey) {
        keys.push("alt");
    }
    if (event.metaKey) {
        keys.push("meta");
    }
    alert("Keys: " + keys.join(","));
});

DOM通过event 对象的relatedTarget 属性提供了相关元素的信
只对于mouseover和mouseout 事件才包含值,其它值是null
IE8及之前版本不支持relatedTarget

mouseover -->IE 的fromElement
mouseout --》IE 的toElement

继续完善

        var EventUtil = {
            addHandler: function(element, type, handler) {
                if (element.addEventListener) {
                    element.addEventListener(type, handler, false);
                } else if (element.attachEvent) {
                    element.attachEvent("on" + type, handler);
                } else {
                    element["on" + type] = handler;
                }
            },
            getEvent: function(event) {
                return event ? event : window.event;
            },
            getTarget: function(event) {
                return event.target || event.srcElement;
            },
            preventDefault: function(event) {
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            },
            removeHandler: function(element, type, handler) {
                if (element.removeEventListener) {
                    element.removeEventListener(type, handler, false);
                } else if (element.detachEvent) {
                    element.detachEvent("on" + type, handler);
                } else {
                    element["on" + type] = null;
                }
            },
            stopPropagation: function(event) {
                if (event.stopPropagation) {
                    event.stopPropagation();
                } else {
                    event.cancelBubble = true;
                }
            },
            getRelatedTarget: function(event) {
                if (event.relatedTarget) {
                    return event.relatedTarget;
                } else if (event.toElement) {
                    return event.toElement;
                } else if (event.fromElement) {
                    return event.fromElement;
                } else {
                    return null;
                }
            }

        };

    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "mouseout", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    var relatedTarget = EventUtil.getRelatedTarget(event);
    alert("Moused out of " + target.tagName + " to " + relatedTarget.tagName);
    //Moused out of DIV to BODY

鼠标按钮
DOM的button 属性可能有如下3 个值:0 表示主鼠标按钮,1 表示中间的鼠
标按钮(鼠标滚轮按钮),2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标
按钮就是鼠标右
最常见的做法就是将IE 模型规范化为DOM 方式

添加getButton

var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },
    getRelatedTarget: function(event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
    },
    getButton: function(event) {
        if (document.implementation.hasFeature("MouseEvents", "2.0")) {
            return event.button;
        } else {
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    }
};

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "mousedown", function(event) {
    event = EventUtil.getEvent(event);
    alert(EventUtil.getButton(event)); //左0 中1 右2
});

鼠标滚轮:
mousewheel 事件时显示wheelDelta 的值,
ff:支持:DOMMouseScroll

EventUtil.addHandler(document, "mousewheel", function(event){
event = EventUtil.getEvent(event);
console.log(event.wheelDelta); //上120,下-120
});

//ff

EventUtil.addHandler(window, "DOMMouseScroll", function(event) {
    event = EventUtil.getEvent(event); // 上-3  下3
    alert(event.detail);
});

整合添加:

var EventUtil = {
addHandler: function(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + type, handler);
    } else {
        element["on" + type] = handler;
    }
},
getEvent: function(event) {
    return event ? event : window.event;
},
getTarget: function(event) {
    return event.target || event.srcElement;
},
preventDefault: function(event) {
    if (event.preventDefault) {
        event.preventDefault();
    } else {
        event.returnValue = false;
    }
},
removeHandler: function(element, type, handler) {
    if (element.removeEventListener) {
        element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
        element.detachEvent("on" + type, handler);
    } else {
        element["on" + type] = null;
    }
},
stopPropagation: function(event) {
    if (event.stopPropagation) {
        event.stopPropagation();
    } else {
        event.cancelBubble = true;
    }
},
getRelatedTarget: function(event) {
    if (event.relatedTarget) {
        return event.relatedTarget;
    } else if (event.toElement) {
        return event.toElement;
    } else if (event.fromElement) {
        return event.fromElement;
    } else {
        return null;
    }
},
getButton: function(event) {
    if (document.implementation.hasFeature("MouseEvents", "2.0")) {
        return event.button;
    } else {
        switch (event.button) {
            case 0:
            case 1:
            case 3:
            case 5:
            case 7:
                return 0;
            case 2:
            case 6:
                return 2;
            case 4:
                return 1;
        }
    }
},
getWheelDelta: function(event) {
    if (event.wheelDelta) {
        return (event.wheelDelta);
    } else {
        return -event.detail * 40;
    }
}
}

//使用
//handleMouseWheel()函数可以用作两个事件的处理程序(如果指定的事件不存在,则为该事件指定处
理程序的代码就会静默地失败)
function handleMouseWheel(event){
    event = EventUtil.getEvent(event);
    var delta = EventUtil.getWheelDelta(event);
    alert(delta); //下-120,上120
}
EventUtil.addHandler(document, "mousewheel", handleMouseWheel);
EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel);

键盘与文本
键盘事件:
keydown当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件
keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。
按下Esc 键也会触发这个事件。Safari 3.1 之前的版本也会在用户按下非字符键时触发keypress
事件。
keyup:当用户释放键盘上的键时触发。
文本事件:textInput,对keypress补充

按下字符:keydown--》keypress【前两个是文本变化之前】--》keyup
连续按:连接触发:keydown--》keypress

按下非字符:keydown --》keyup
也有shiftKey、ctrlKey、altKey 和metaKey[非IE] 属性

键码
在发生keydown 和keyup 事件时,event 对象的keyCode 属性中会包含一个代码

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keyup", function(event) {
    event = EventUtil.getEvent(event);
    alert(event.keyCode); //显示keyCode值
});
var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },
    getRelatedTarget: function(event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
    },
    getButton: function(event) {
        if (document.implementation.hasFeature("MouseEvents", "2.0")) {
            return event.button;
        } else {
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    },
    getWheelDelta: function(event) {
        if (event.wheelDelta) {
            return (event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
    getCharCode: function(event) {
        if (typeof event.charCode == "number") {
            return event.charCode;
        } else {
            return event.keyCode;
        }
    }
}

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keypress", function(event) {
    event = EventUtil.getEvent(event);
    alert(EventUtil.getCharCode(event));//值出字符编码
});

之后可以使用String.fromCharCode(number),再转为正常字符;

所有非字符

特殊情况: ff o 分号键keyCode = 59 【ASCII分号编码】; ie safari分号键 = 186;【按键编码】

由于存在跨浏览器问题,因此本书不推荐使用key、keyIdentifier 或char。

textInput事件
替代keypress 的textInput 事件的行为稍有不同。
区别一:就是任何可以获得焦点的元素都可以触发keypress 事件,但只有可编辑区域才能触发textInput事件。
区别二:textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,
而keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。

由于textInput 事件主要考虑的是字符,因此它的event 对象中还包含一个data 属性,这个属
性的值就是用户输入的字符(而非字符编码)。换句话说,用户在没有按上档键的情况下按下了S 键,
data 的值就是"s",而如果在按住上档键时按下该键,data 的值就是"S"。

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "textInput", function(event){
event = EventUtil.getEvent(event);
alert(event.data); //按下什么输出什么
});

HTML5事件

  1. contextmenu 事件显示菜单,支持contextmenu 事件的浏览器有IE、Firefox、Safari、Chrome 和Opera 11+。
EventUtil.addHandler(window, "load", function(event) {
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "contextmenu", function(event) {
        event = EventUtil.getEvent(event);
        EventUtil.preventDefault(event);
        var menu = document.getElementById("myMenu");
        menu.style.left = event.clientX + "px";
        menu.style.top = event.clientY + "px";
        menu.style.visibility = "visible";
    });
    EventUtil.addHandler(document, "click", function(event) {
        document.getElementById("myMenu").style.visibility = "hidden";
    });
});
  1. beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作,为了显示这个弹出对话框,必须将event.returnValue 的值设置为要显示给用户的字符串(对IE 及Fiefox 而言),同时作为函数的值返回
    [

returnValue Boolean 读/写 默认值为true,但将其设置为false就可以取消事件的默认行为(与
DOM中的preventDefault()方法的作用相同)
]

EventUtil.addHandler(window, "beforeunload", function(event) {
    event = EventUtil.getEvent(event);
    var message = "I'm really going to miss you if you go.";
    event.returnValue = message;
    return message;
});
  1. DOMContentLoaded 事件 DOM加载完成后触发;
    要处理DOMContentLoaded 事件,可以为document 或window 添加相应的事件处理程序(尽管

这个事件会冒泡到window,但它的目标实际上是document)。来看下面的例子。
注:这个事件始终都会在load 事件之前触发

EventUtil.addHandler(document, "DOMContentLoaded", function(event){
    alert("Content loaded");
});

不支持的浏览器使用:

setTimeout(function(){
//在此添加事件处理程序
}, 0);
  1. readystatechange 事件
    支持readystatechange 事件的每个对象都有一个readyState 属性

uninitialized(未初始化):对象存在但尚未初始化。
loading(正在加载):对象正在加载数据。
loaded(加载完毕):对象加载数据完成。
interactive(交互):可以操作对象了,但还没有完全加载。
complete(完成):对象已经加载完毕。

不支持则会跳过,所以一般readystatechange事件经常会少于4次;而readyState则总是不连续;

EventUtil.addHandler(document, "readystatechange", function(event) {
    if (document.readyState == "interactive") {
        alert("Content loaded");
    }
});

同时检测交互和完成阶

EventUtil.addHandler(document, "readystatechange", function(event) {
    if (document.readyState == "interactive" || document.readyState == "complete") {
        EventUtil.removeHandler(document, "readystatechange", arguments.callee);
        alert("Content loaded");
    }
});

对于上面的代码来说,当readystatechange 事件触发时,会检测document.readyState 的值,
看当前是否已经进入交互阶段或完成阶段。如果是,则移除相应的事件处理程序以免在其他阶段再执行。
注意,由于事件处理程序使用的是匿名函数,因此这里使用了arguments.callee 来引用该函数。然
后,会显示一个警告框,说明内容已经加载完毕。这样编写代码可以达到与使用DOMContentLoaded
十分相近的效

下面展示了一段加载外部JavaScript/css 文件的代码

//js
EventUtil.addHandler(window, "load", function() {
    var script = document.createElement("script");
    EventUtil.addHandler(script, "readystatechange", function(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.readyState == "loaded" || target.readyState == "complete") {
            EventUtil.removeHandler(target, "readystatechange", arguments.callee);
            alert("Script Loaded");
        }
    });
    script.src = "example.js";
    document.body.appendChild(script);
});

//css
EventUtil.addHandler(window, "load", function() {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    EventUtil.addHandler(script, "readystatechange", function(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.readyState == "loaded" || target.readyState == "complete") {
            EventUtil.removeHandler(target, "readystatechange", arguments.callee);
            alert("CSS Loaded");
        }
    });
    link.href = "example.css";
    document.getElementsByTagName("head")[0].appendChild(link);
});
  1. pageshow 和pagehide 事件

(略)

  1. hashchange 事件
    必须要把hashchange 事件处理程序添加给window 对象,然后URL 参数列表只要变化就会调用

它。此时的event 对象应该额外包含两个属性:oldURL 和newURL。这两个属性分别保存着参数列表
变化前后的完整URL。例如:

EventUtil.addHandler(window, "hashchange", function(event){
    alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
}); //前后变化,完整url

EventUtil.addHandler(window, "hashchange", function(event){
    alert("Current hash: " + location.hash);
});//当前 #后字符

检测是否支持

var isSupported = ("onhashchange" in window) && (document.documentMode ===
undefined || document.documentMode > 7);

13.4.8 设备事件

  1. orientationchange 事件

苹果公司为移动Safari 中添加了orientationchange 事件,以便开发人员能够确定用户何时将设
备由横向查看模式切换为纵向查看模式。移动Safari 的window.orientation 属性中可能包含3 个值:
0 表示肖像模式,90 表示向左旋转的横向模式(“主屏幕”按钮在右侧),-90 表示向右旋转的横向模
式(“主屏幕”按钮在左侧)。相关文档中还提到一个值,即180 表示iPhone 头朝下;但这种模式至今
尚未得到支持。图13-10 展示了window.orientation 的每个值的含义

只要用户改变了设备的查看模式,就会触发orientationchange 事件。此时的event 对象不包
含任何有价值的信息,因为唯一相关的信息可以通过window.orientation 访问到。下面是使用这个
事件的典型示例

EventUtil.addHandler(window, "load", function(event) {
    var div = document.getElementById("myDiv");
    div.innerHTML = "Current orientation is " + window.orientation;
//改变时触发
    EventUtil.addHandler(window, "orientationchange", function(event) {
        div.innerHTML = "Current orientation is " + window.orientation;
    });
});
//横屏
window.orientation == 90 || window.orientation == -90
//竖屏
window.orientation == 0 || window.orientation == 180
//粗略检测,并不准,ie都返回false
alert(document.implementation.hasFeature("orientationchange", "2.0"))
  1. deviceorientation 事件
  2. 事件的意图是告诉开发人员设备在空间中朝向哪儿,而不是如何移动;

设备在三维空间中是靠x、y 和z 轴来定位的 三个值都是0

x轴: 左 --》 右;
y轴: 下 --》 上;
z轴: 后 --》 前;

事件对象包含以下5 个属性。
 alpha:在围绕z 轴旋转时(即左右旋转时),y 轴的度数差;是一个介于0 到360 之间的浮点数。
 beta:在围绕x 轴旋转时(即前后旋转时),z 轴的度数差;是一个介于180 到180 之间的浮点数。
 gamma:在围绕y 轴旋转时(即扭转设备时),z 轴的度数差;是一个介于90 到90 之间的浮点数。
 absolute:布尔值,表示设备是否返回一个绝对值。
 compassCalibrated:布尔值,表示设备的指南针是否校准过。

13.4.9 触摸与手势事件

touchstart/touchmove/touchend/touchcancel
每個event對象都有以下常見屬性;
bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和metaKey。

touches:表示当前跟踪的触摸操作的Touch 对象的数组。
 targetTouchs:特定于事件目标的Touch 对象的数组。
 changeTouches:表示自上次触摸以来发生了什么改变的Touch 对象的数组。
每个Touch 对象包含下列属性。

clientX:触摸目标在视口中的x 坐标。
 clientY:触摸目标在视口中的y 坐标。
 identifier:标识触摸的唯一ID。
 pageX:触摸目标在页面中的x 坐标。
 pageY:触摸目标在页面中的y 坐标。
 screenX:触摸目标在屏幕中的x 坐标。
 screenY:触摸目标在屏幕中的y 坐标。
 target:触摸的DOM 节点目标。
使用这些属性可以跟踪用户对屏幕的

function handleTouchEvent(event) {
    if (event.touches.length == 1) {
        var _output = document.getElementById('output')
        switch (event.type) {
            case 'touchstart':
                _output.innerHTML = 'Touch started' + event.touches[0].clientX + ',' + event.touches[0].clientY
                break;
            case 'touchend':
                _output.innerHTML += '<br> Touche ended' + event.changedTouches[0].clientX + ':' +
                    event.changedTouches[0].clientY + ';';
                break;
            case 'touchmove':
                event.preventDefault();
                _output.innerHTML += '<br> Touch move' +
                    event.changedTouches[0].clientX + ':' +
                    event.changedTouches[0].clientY + ';';
                break;
        }
    }
}

EventUtil.addHandler(document, 'touchstart', handleTouchEvent)
EventUtil.addHandler(document, 'touchend', handleTouchEvent)
EventUtil.addHandler(document, 'touchmove', handleTouchEvent)

當touchstart發生: 觸摸信息輸出到<div>中 當touchmove發生:取消默認行為,阻止滾動,輸出變化信息
當touchend發生時:輸出有關觸摸操作信息,在touchend發生時:touches集合中就沒有任何信息,因為不存在活動觸摸操作,此時必須使用changeTouches集合

發生順序如下:

(1) touchstart
(2) mouseover
(3) mousemove(一次)
(4) mousedown
(5) mouseup
(6) click
(7) touchend

  1. 手势事件

當兩個手指觸摸時,就會產生手勢,手勢通常會改變顯示項大小,或旋轉顯示項,三個事件

 gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
 gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。
 gestureend:当任何一个手指从屏幕上面移开时触发。

当一个手指在屏幕时,触发touchstart
另一个手指放在屏幕,先触发gesturestart事件,随后触发该手指的touchstart
如果一个或两个手指在屏幕移动,触发gesturechange事件,但只要有一手指移开,触发gestureend事件,
最后再触发该手指的touchend事件;

每个event对象包含::
bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、
ctrlKey 和metaKey、还有两个额外属性:rotation、scale

rotation: 表示手指变化引起的旋转角度, -值逆时针,+ 顺时针(该值从0开始)
scale: 表示两个手指距离变化情况,如内收缩会缩短距离,从1开始;

function handleTouchEvent(event) {

    var _output = document.getElementById('output')
    switch (event.type) {
        case 'gesturestart':
            _output.innerHTML = 'Gesture started rotation = ' + event.rotation + ', scale' + event.scale;
            break;
        case 'gestureend':
            _output.innerHTML += '<br> Gesture end rotation = ' + event.rotation + ', scale' + event.scale;
            break;
        case 'gesturechange':
            event.preventDefault();
            _output.innerHTML += '<br> Gesture change rotation = ' + event.rotation + ', scale' + event.scale;
            break;
    }
}

EventUtil.addHandler(document, 'gesturestart', handleTouchEvent)
EventUtil.addHandler(document, 'gestureend', handleTouchEvent)
EventUtil.addHandler(document, 'gesturechange', handleTouchEvent)

13.5.1 事件委托

var list = document.getElementById('myLinks')
EventUtil.addHandler(list, 'click', function(event) { //父级绑定click
    event = EventUtil.getEvent(event)
    var target = EventUtil.getTarget(event)
    switch (target.id) {  //检测目标元素属性
        case 'doSomething':
            document.title = 'i cahnge the document is ttile'
            break;
        case 'goSomewhere':
            location.href = 'http://www.x.com';
            break;
        case 'sayHi':
            alert('hi')
            break;
    }
})
var btn = document.getElementById('myBtn')
btn.onclick = function(){
    document.getElementById('myDiv').innerHTML = 'processing'  //按钮被替换了,但click事件还在
}

//所以
var btn = document.getElementById('myBtn')
btn.onclick = function(){
    btn.onclick = null; //先移除
    document.getElementById('myDiv').innerHTML = 'processing'  //按钮被替换了,但click事件还在
}

13.6.1 DOM中的事件模拟

  1. 模拟鼠标事件
    创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是

为createEvent()传入字符串"MouseEvents"。返回的对象有一个名为initMouseEvent()方法,
用于指定与该鼠标事件有关的信息。这个方法接收15 个参数,分别与鼠标事件中每个典型的属性一一
对应;这些参数的含义如下。

对应;这些参数的含义如下。
 type(字符串):表示要触发的事件类型,例如"click"。
 bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为
true。
 cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设
置为true。
 view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.defaultView。
 detail(整数):与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为0。
 screenX(整数):事件相对于屏幕的X 坐标。
 screenY(整数):事件相对于屏幕的Y 坐标。
 clientX(整数):事件相对于视口的X 坐标。
 clientY(整数):事件想对于视口的Y 坐标。
 ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
 altKey(布尔值):表示是否按下了Alt 键。默认值为false。
 shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
 metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
 button(整数):表示按下了哪一个鼠标键。默认值为0。
 relatedTarget(对象):表示与事件相关的对象。这个参数只在模拟mouseover 或mouseout
时使用。

var btn = document.getElementById('myBtn')

//创建事件对象
var event = document.createEvent('mouseEvents')

//初始化
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
false, false, false, false, 0, null);

//触发
btn.dispatchEvent(event)
  1. 模拟键盘事件
    一、DOM3 级规定,调用createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的

事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数
 type(字符串):表示要触发的事件类型,如"keydown"。
 bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
 cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
 view (AbstractView ):与事件关联的视图。这个参数几乎总是要设置为document.
defaultView。
 key(布尔值):表示按下的键的键码。
 location(整数):表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示
数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
 modifiers(字符串):空格分隔的修改键列表,如"Shift"。
 repeat(整数):在一行中按了这个键多少次。

DOM3级不提倡使用keypress 事件,因此只能利用这种技术来模拟keydown 和keyup 事件。

var textbox = document.getElementById("myTextbox"),
    event;
//以DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")) {
    event = document.createEvent("KeyboardEvent");
    //初始化事件对象
    event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, "Shift", 0);
}
//触发事件
textbox.dispatchEvent(event);

这个例子模拟的是按住Shift 的同时又按下A 键。在使用document.createEvent
("KeyboardEvent")之前,应该先检测浏览器是否支持DOM3 级事件;其他浏览器返回一个非标准的
KeyboardEvent 对象。

二、在Firefox 中,调用createEvent()并传入"KeyEvents"就可以创建一个键盘事件。返回的事件
对象会包含一个initKeyEvent()方法,这个方法接受下列10 个参数。

 type(字符串):表示要触发的事件类型,如"keydown"。
 bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
 cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
 view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.default-
View。
 ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
 altKey(布尔值):表示是否按下了Alt 键。默认值为false。
 shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
 metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
 keyCode(整数):被按下或释放的键的键码。这个参数对keydown 和keyup 事件有用,默认
值为0。
 charCode(整数):通过按键生成的字符的ASCII 编码。这个参数对keypress 事件有用,默
认值为0。

//只适用于Firefox
var textbox = document.getElementById("myTextbox")
//创建事件对象
var event = document.createEvent("KeyEvents");
//初始化事件对象
event.initKeyEvent("keypress", true, true, document.defaultView, false, false,
false, false, 65, 65);
//触发事件
textbox.dispatchEvent(event);

三、其它浏览器
首先创建了一个通用事件,然后调用initEvent()对其进行初始化,最后又为其添加了
键盘事件的具体信息。在此必须要使用通用事

var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEvent("Events");
//初始化事件对象
event.initEvent(type, bubbles, cancelable);
event.view = document.defaultView;
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.metaKey = false;
event.keyCode = 65;
event.charCode = 65;
//触发事件
textbox.dispatchEvent(event);
  1. 模拟其他事件
    模拟变动事件, 可以使用createEvent("MutationEvents") 创建一个包含

initMutationEvent() 方法的变动事件对象。这个方法接受的参数包括: type 、bubbles 、
cancelable、relatedNode、preValue、newValue、attrName 和attrChange。下面来看一个模
拟变动事件的例子。

var event = document.createEvent("MutationEvents");
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
targ et.dispatchEvent(event);

以上代码模拟了DOMNodeInserted

  1. 自定义DOM 事件

创建新的自定义事件,可以调用createEvent("CustomEvent")。返回的对象有一个名为initCustomEvent()的方法

var div = document.getElementById("myDiv"),
    event;
EventUtil.addHandler(div, "myevent", function(event) {
    alert("DIV: " + event.detail);
});
EventUtil.addHandler(document, "myevent", function(event) {
    alert("DOCUMENT: " + event.detail);
});
if (document.implementation.hasFeature("CustomEvents", "3.0")) {
    event = document.createEvent("CustomEvent");
    event.initCustomEvent("myevent", true, false, "Hello world!");
    div.dispatchEvent(event);
}

创建了一个冒泡事件"myevent"。而event.detail 的值被设置成了一个简单的字符串,
然后在<div>元素和document 上侦听这个事件。因为initCustomEvent()方法已经指定这个事件应
该冒泡,所以浏览器会负责将事件向上冒泡到document。

支持自定义DOM事件的浏览器有IE9+和Firefox 6+。

13.6.2 IE中的事件模拟
IE8之前的版本
思路相似:先创建event 对象,然后为其指定相应的信息,然后再使用该对象来触发事件
调用document.createEventObject()方法可以在IE 中创建event 对象。但与DOM方式不同的是,这个方法不接受参数,结果会返回一个通用的event 对象
最后一步就是在目标上调用fireEvent()方法

fireEvent(事件处理程序的名称,event对象)

在调用fireEvent()方法时,会自动为event 对象添加srcElement 和type 属性

其他属性则都是必须通过手工添加的。换句话说,模拟任
何IE 支持的事件都采用相同的模式。例如,下面的代码模拟了在一个按钮上触发click 事件过程

var btn = document.getElementById("myBtn");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.screenX = 100;
event.screenY = 0;
event.clientX = 0;
event.clientY = 0;
event.ctrlKey = false;
event.altKey = false;
event.shiftKey = false;
event.button = 0;
//触发事件
btn.fireEvent("onclick", event);

//触发keypress事件

var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.keyCode = 65;
//触发事件
textbox.fireEvent("onkeypress", event);