JS之事件

JavaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码。

一、事件流

事件流描述的是从页面中接收事件的顺序。

1、事件冒泡

IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

<!DOCTYPE html>
<html>
<head>
    <title>Event Bubbling Example</title>
</head>
<body>
    <div id="myDiv">Click Me</div>
</body>
</html>
//如果你单击了页面中的 <div> 元素,那么这个 click 事件会按照如下顺序传播:
(1)  <div>
(2)  <body>
(3)  <html>
(4)  document

所有现代浏览器都支持事件冒泡,但在具体实现上存在一些差别。

2、事件捕获

事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。
事件捕获触发的 click 事件:

(1) document
(2) <html>
(3) <body>
(4) <div>

由于老版本的浏览器不支持,因此很少有人使用事件捕获。

3、DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。


二、事件处理程序

响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以 "on" 开头,因此click 事件的事件处理程序就是 onclick , load 事件的事件处理程序就是 onload 。

1、HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个特性的值应该是能够执行的 JavaScript 代码。

// HTML 中定义的事件
<input type="button" value="Click Me" onclick="alert('Clicked')" />
//调用脚本形式
<input type="button" value="Click Me" onclick="showMessage()" />
<script type="text/javascript">
function showMessage(){
    alert("Hello world!");
}
</script>

2、DOM0级事件处理程序

通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代 Web 浏览器中出现的,而且至今仍然为所有现代浏览器所支持。原因一是简单,二是具有跨浏览器的优势。要使用 JavaScript 指定事件处理程序,首先必须取得一个要操作的对象的引用。

每个元素(包括 window 和 document )都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick 。将这种属性的值设置为一个函数,就可以指定事件处理程序。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert("Clicked");
};

通过文档对象取得了一个按钮的引用,然后为它指定了 onclick 事件处理程序。

使用 DOM0 级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的 this 引用当前元素。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(this.id); //"myBtn"
};

不仅仅是 ID,实际上可以在事件处理程序中通过 this 访问元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

也可以删除通过 DOM0 级方法指定的事件处理程序。

btn.onclick = null; //删除事件处理程序

将事件处理程序设置为 null 之后,再单击按钮将不会有任何动作发生。

3、DOM2级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener()和 removeEventListener() 。所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true ,表示在捕获阶段调用事件处理程序;如果是 false ,表示在冒泡阶段调用事件处理程序。

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
    alert(this.id);
}, false);

通过 addEventListener() 添加的事件处理程序只能使用 removeEventListener() 来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener() 添加的匿名函数将无法移除。

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
    alert(this.id);
}, false);
// 匿名函数
btn.removeEventListener("click", function(){ // 没有用!
    alert(this.id);
}, false);

var handler = function(){
    alert(this.id);
};
btn.addEventListener("click", handler, false);
// 传入函数名
btn.removeEventListener("click", handler, false); // 有效!

传入 removeEventListener() 中的事件处理程序函数必须与传入addEventListener() 中的相同。

4、IE事件处理程序

IE 实现了与 DOM 中类似的两个方法: attachEvent() 和 detachEvent() 。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
    alert("Clicked");
});

注意, attachEvent() 的第一个参数是 "onclick" ,而非 DOM 的 addEventListener() 方法中的 "click" 。

在 IE 中使用 attachEvent() 与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window 。

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

使用 attachEvent() 添加的事件可以通过 detachEvent() 来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将对相同函数的引用传给 detachEvent() ,就可以移除相应的事件处理程序。

var btn = document.getElementById("myBtn");
var handler = function(){
    alert("Clicked");
};
btn.attachEvent("onclick", handler);
// 移除相应事件
btn.detachEvent("onclick", handler);

5、跨浏览器的事件处理程序

addHandler() 方法接受 3 个参数:要操作的元素、事件名称和事件处理程序函数。它的职责是视情况分别使用 DOM0 级方法、DOM2 级方法或 IE 方法来添加事件。这个方法属于一个名叫 EventUtil 的对象。

与 addHandler() 对应的方法是 removeHandler() ,它也接受相同的参数。这个方法的职责是移除之前添加的事件处理程序。

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;
        }
    }
};

使用 EventUtil 对象:

var btn = document.getElementById("myBtn");
var handler = function(){
    alert("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
// 这里省略了其他代码
EventUtil.removeHandler(btn, "click", handler);

三、事件对象

在触发 DOM 上的某个事件时,会产生一个事件对象 event ,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。

1、DOM中的事件对象

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
    alert(event.type); //"click"
}, false);
//通过 HTML 特性指定事件处理程序时,变量 event 中保存着 event 对象
<input type="button" value="Click Me" onclick="alert(event.type)"/>

event 对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。



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

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert(event.currentTarget === this); //true
    alert(event.target === this); //true
};
//事件处理程序存在于按钮的父节点中
document.body.onclick = function(event){
    alert(event.currentTarget === document.body); //true
    alert(this === document.body); //true
    alert(event.target === document.getElementById("myBtn")); //true
};

在需要通过一个函数处理多个事件时,可以使用 type 属性。

var btn = document.getElementById("myBtn");
var handler = function(event) {
    switch (event.type) {
        case "click":
            alert("Clicked");
            break;
        case "mouseover":
            event.target.style.backgroundColor = "red";
            break;
        case "mouseout":
            event.target.style.backgroundColor = "";
            break;
    }
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

要阻止特定事件的默认行为,可以使用 preventDefault() 方法。例如,阻止链接的默认行为:

var link = document.getElementById("myLink");
link.onclick = function(event){
    event.preventDefault();
};

只有 cancelable 属性设置为 true 的事件,才可以使用 preventDefault() 来取消其默认行为。

stopPropagation() 方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert("Clicked");
    event.stopPropagation();
};
document.body.onclick = function(event){
    alert("Body clicked");
};

如果不调用 stopPropagation() ,就会在单击按钮时出现两个警告框。

事件对象的 eventPhase 属性,可以用来确定事件当前正位于事件流的哪个阶段。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert(event.eventPhase); //2
};
document.body.addEventListener("click", function(event){
    alert(event.eventPhase); //1
}, true);
document.body.onclick = function(event){
    alert(event.eventPhase); //3
};

提示:只有在事件处理程序执行期间, event 对象才会存在;一旦事件处理程序执行完成, event 对象就会被销毁。

2、IE中的事件对象

与访问 DOM 中的 event 对象不同,要访问 IE 中的 event 对象有几种不同的方式,取决于指定事件处理程序的方法。

在使用 DOM0 级方法添加事件处理程序时, event 对象作为 window 对象的一个属性存在。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    var event = window.event;
    alert(event.type); //"click"
};

如果事件处理程序是使用 attachEvent() 添加的,那么就会有一个 event 对象作为参数被传入事件处理程序函数中。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event){
    alert(event.type); //"click"
});

如果是通过HTML特性指定的事件处理程序,那么还可以通过一个名叫 event 的变量来访问 event对象(与 DOM中的事件模型相同)。

<input type="button" value="Click Me" onclick="alert(event.type)">

IE 的 event 对象同样也包含与创建它的事件相关的属性和方法。



因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为 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
});

returnValue 属性相当于 DOM中的 preventDefault() 方法,作用都是取消
给定事件的默认行为。只要将 returnValue 设置为 false ,就可以阻止默认行为。

var link = document.getElementById("myLink");
link.onclick = function(){
    window.event.returnValue = false;
};

cancelBubble 属性与 DOM 中的 stopPropagation() 方法作用相同,都是用来停止事件冒泡的。但 stopPropagatioin() 可以同时取消事件捕获和冒泡。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert("Clicked");
    window.event.cancelBubble = true;
};
document.body.onclick = function(){
    alert("Body clicked");
}; 

3、跨浏览器的事件对象

虽然 DOM 和 IE 中的 event 对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来。

var EventUtil = {
    addHandler: function(element, type, handler) {
        //省略的代码
    },
   //返回对 event对象的引用。
    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) {
        //省略的代码
    },
    //取消事件捕获和冒泡
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

var btn = document.getElementById("myBtn");
// getEvent()的使用方法
btn.onclick = function(event) {
    event = EventUtil.getEvent(event);
};
// getTarget()的使用方法
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);
};
//
btn.onclick = function(event) {
    alert("Clicked");
    event = EventUtil.getEvent(event);
    EventUtil.stopPropagation(event);
};
document.body.onclick = function(event) {
    alert("Body clicked");
};

stopPropagation()方法由于 IE 不支持事件捕获,因此这个方法在跨浏览器的情况下,只能用来阻止事件冒泡。

四、事件类型

“DOM3级事件”规定了以下几类事件:

  • UI(User Interface,用户界面)事件,当用户与页面上的元素交互时触发;
  • 焦点事件,当元素获得或失去焦点时触发;
  • 鼠标事件,当用户通过鼠标在页面上执行操作时触发;
  • 滚轮事件,当使用鼠标滚轮(或类似设备)时触发;
  • 文本事件,当在文档中输入文本时触发;
  • 键盘事件,当用户通过键盘在页面上执行操作时触发;
  • 合成事件,当为 IME(Input Method Editor,输入法编辑器)输入字符时触发;
  • 变动(mutation)事件,当底层 DOM 结构发生变化时触发。
  • 变动名称事件,当元素或属性名变动时触发。此类事件已经被废弃

1、UI事件

UI 事件指的是那些不一定与用户操作有关的事件。

  • load :当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在 <img> 元素上面触发,或者当嵌入的内容加载完毕时在 <object> 元素上面触发。
  • unload :当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在 <object> 元素上面触发。
  • abort :在用户停止下载过程时,如果嵌入的内容没有加载完,则在 <object> 元素上面触发。
  • error :当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在 <img> 元素上面触发,当无法加载嵌入内容时在 <object> 元素上面触发,或者当有一或多个框架无法加载时在框架集上面触发。
  • select :当用户选择文本框( <input> 或 <texterea> )中的一或多个字符时触发
  • resize :当窗口或框架的大小变化时在 window 或框架上面触发。
  • scroll :当用户滚动带滚动条的元素中的内容时,在该元素上面触发。 <body> 元素中包含所加载页面的滚动条。

要确定浏览器是否支持 DOM2 级事件规定的 HTML 事件:

var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");

注意,只有根据“DOM2 级事件”实现这些事件的浏览器才会返回 true 。而以非标准方式支持这些事件的浏览器则会返回 false 。

要确定浏览器是否支持“DOM3 级事件”定义的事件:

var isSupported = document.implementation.hasFeature("UIEvent", "3.0");

(1) load 事件

load 事件JavaScript 中最常用的一个事件就是 load 。当页面完全加载后(包括所有图像、JavaScript 文件、CSS 文件等外部资源),就会触发 window 上面的 load 事件。

有两种定义 onload 事件处理程序的方式。
第一种:通过 JavaScript 来指定事件处理程序的方式,使用了跨浏览器的 EventUtil对象。

EventUtil.addHandler(window, "load", function(event){
    alert("Loaded!");
});

第二种:指定 onload 事件处理程序的方式是为 <body> 元素添加一个 onload 特性。

<!DOCTYPE html>
<html>
<head>
<title>Load Event Example</title>
</head>
<body onload="alert('Loaded!')">
</body>
</html>

建议尽可能使用 JavaScript 方式。

(2)unload事件

与 load 事件对应的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。

有两种指定 onunload 事件处理程序的方式。
第一种方式是使用 JavaScript:

EventUtil.addHandler(window, "unload", function(event){
    alert("Unloaded");
});

指定事件处理程序的第二种方式,为 <body> 元素添加一个特性:

<!DOCTYPE html>
<html>
<head>
<title>Unload Event Example</title>
</head>
<body onunload="alert('Unloaded!')">
</body>
</html>

(3) resize 事件

当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。可以通过 JavaScript 或者 <body> 元素中的 onresize 特性来指定事件处理程序。

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

提示:浏览器窗口最小化或最大化时也会触发 resize 事件。

(4)scroll事件

虽然 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。

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

2、焦点事件

焦点事件会在页面元素获得或失去焦点时触发。

  • blur :在元素失去焦点时触发。这个事件不会冒泡;
  • focus :在元素获得焦点时触发。这个事件不会冒泡;
  • focusin :在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡。
  • focusout :在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本。

最主要的两个是 focus 和 blur 。

3、鼠标与滚轮事件

DOM3 级事件中定义了 9 个鼠标事件:

  • click :在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发。
  • dblclick :在用户双击主鼠标按钮(一般是左边的按钮)时触发。
  • mousedown :在用户按下了任意鼠标按钮时触发。
  • mouseenter :在鼠标光标从元素外部首次移动到元素范围之内时触发。
  • mouseleave :在位于元素上方的鼠标光标移动到元素范围之外时触发。
  • mousemove :当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
  • mouseout :在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘触发这个事件。
  • mouseover :在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件。
  • mouseup :在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。

除了 mouseenter 和 mouseleave ,所有鼠标事件都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。

只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果mousedown 或 mouseup 中的一个被取消,就不会触发 click 事件。

(1)客户区坐标位置

鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的 clientX 和clientY 属性中。所有浏览器都支持这两个属性,它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。

取得鼠标事件的客户端坐标信息:

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

(2)页面坐标位置

页面坐标通过事件对象的 pageX 和pageY 属性,能告诉你事件是在页面中的什么位置发生的。换句话说,这两个属性表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的。

取得鼠标事件在页面中的坐标:

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

IE8 及更早版本不支持事件对象上的页面坐标,可以使用客户区坐标和滚动信息可以计算出来。

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);
});

(3)屏幕坐标位置

鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而通过 screenX 和 screenY 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。

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

(4)修改键

这些修改键就是 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(","));
});

(5)鼠标按钮

只有在主鼠标按钮被单击(或键盘回车键被按下)时才会触发 click 事件,因此检测按钮的信息并不是必要的。

DOM 的 button 属性可能有如下 3 个值: 0 表示主鼠标按钮, 1 表示中间的鼠标按钮(鼠标滚轮按钮), 2 表示次鼠标按钮。

(6)鼠标滚轮事件

当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel事件。

IE 6.0 首先实现了 mousewheel 事件。此后,Opera、Chrome 和 Safari 也都实现了这个事件。

与 mousewheel 事件对应的 event 对象除包含鼠标事件的所有标准信息外,还包含一个特殊的 wheelDelta 属性。当用户向前滚动鼠标滚轮时, wheelDelta 是 120 的倍数;当用户向后滚动鼠标滚轮时, wheelDelta 是-120 的倍数。

EventUtil.addHandler(document, "mousewheel", function(event){
    event = EventUtil.getEvent(event);
    alert(event.wheelDelta);
});

Firefox 支持一个名为 DOMMouseScroll 的类似事件,也是在鼠标滚轮滚动时触发。有关鼠标滚轮的信息则保存在 detail 属性中,当向前滚动鼠标滚轮时,这个属性的值是 -3 的倍数,当向后滚动鼠标滚轮时,这个属性的值是 3 的倍数。

EventUtil.addHandler(window, "DOMMouseScroll", function(event){
    event = EventUtil.getEvent(event);
    alert(event.detail);
});

跨浏览器环境下的解决方案:

var EventUtil = {
    //省略了其他代码
    getWheelDelta: function(event) {
        if (event.wheelDelta) {
            return (client.engine.opera && client.engine.opera < 9.5 ?
                -event.wheelDelta : event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
    //省略了其他代码
};

getWheelDelta() 方法首先检测了事件对象是否包含 wheelDelta 属性,如果是则通过浏览器检测代码确定正确的值。如果 wheelDelta 不存在,则假设相应的值保存在 detail 属性中。由于Firefox 的值有所不同,因此首先要将这个值的符号反向,然后再乘以 40,就可以保证与其他浏览器的值相同了。

使用示例

(function() {
    function handleMouseWheel(event) {
        event = EventUtil.getEvent(event);
        var delta = EventUtil.getWheelDelta(event);
        alert(delta);
    }
    EventUtil.addHandler(document, "mousewheel", handleMouseWheel);
    EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel);
})();

4、键盘与文本事件

用户在使用键盘时会触发键盘事件。
有 3 个键盘事件:

  • keydown :当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
  • keypress :当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。
  • keyup :当用户释放键盘上的键时触发。

虽然所有元素都支持以上 3 个事件,但只有在用户通过文本框输入文本时才最常用到。

只有一个文本事件: textInput 。这个事件是对 keypress 的补充,用意是在将文本显示给用户之前更容易拦截文本。在文本插入文本框之前会触发 textInput 事件。

在用户按了一下键盘上的字符键时,首先会触发 keydown 事件,然后紧跟着是 keypress 事件,最后会触发 keyup 事件。其中, keydown 和keypress 都是在文本框发生变化之前被触发的;而 keyup事件则是在文本框已经发生变化之后被触发的。如果用户按下了一个字符键不放,就会重复触发keydown 和 keypress 事件,直到用户松开该键为止。

(1)键码

在发生 keydown 和 keyup 事件时, event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。

(2)字符编码

发生 keypress 事件意味着按下的键会影响到屏幕中文本的显示。在所有浏览器中,按下能够插入或删除字符的键都会触发 keypress 事件。

charCode 属性只有在发生keypress 事件时才包含值,而且这个值是按下的那个键所代表字符的 ASCII 编码。

5、HTML5事件

(1) contextmenu 事件

contextmenu 事件用以表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单。

由于 contextmenu 事件是冒泡的,因此可以为 document 指定一个事件处理程序,用以处理页面中发生的所有此类事件。这个事件的目标是发生用户操作的元素。

通常使用 contextmenu 事件来显示自定义的上下文菜单,而使用 onclick 事件处理程序来隐藏该菜单。
HTML结构:

<!DOCTYPE html>
<html>
<head>
    <title>ContextMenu Event Example</title>
</head>
<body>
    <div id="myDiv">Right click or Ctrl+click me to get a custom context menu. Click anywhere else to get the default context menu.</div>
    <ul id="myMenu" style="position:absolute;visibility:hidden;background-color:
silver">
        <li><a href="http://www.nczonline.net">Nicholas’ site</a></li>
        <li><a href="http://www.wrox.com">Wrox site</a></li>
        <li><a href="http://www.yahoo.com">Yahoo!</a></li>
    </ul>
</body>
</html>

JS 部分代码:

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";
    });
});

为 <div> 元素添加了 oncontextmenu 事件的处理程序。这个事件处理程序首先会取消默认行为,以保证不显示浏览器默认的上下文菜单。然后,再根据 event 对象 clientX 和clientY 属性的值,来确定放置 <ul> 元素的位置。最后一步就是通过将 visibility 属性设置为"visible" 来显示自定义上下文菜单。另外,还为 document 添加了一个 onclick 事件处理程序,以便用户能够通过鼠标单击来隐藏菜单(单击也是隐藏系统上下文菜单的默认操作)。
虽然这个例子很简单,但它却展示了 Web 上所有自定义上下文菜单的基本结构。

(2)beforeunload 事件

这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。

(3)DOMContentLoaded 事件

window 的 load 事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要加载的外部资源过多而颇费周折。而 DOMContentLoaded 事件则在形成完整的 DOM树之后就会触发,不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经下载完毕。与 load 事件不同,DOMContentLoaded 支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互。

要处理 DOMContentLoaded 事件,可以为 document 或 window 添加相应的事件处理程序(尽管这个事件会冒泡到 window ,但它的目标实际上是 document )。

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

DOMContentLoaded 事件对象不会提供任何额外的信息(其 target 属性是 document )。

通常这个事件既可以添加事件处理程序,也可以执行其他 DOM 操作。这个事件始终都会在 load 事件之前触发。

(4) readystatechange 事件

IE 为 DOM 文档中的某些部分提供了 readystatechange 事件。这个事件的目的是提供与文档或元素的加载状态有关的信息,但这个事件的行为有时候也很难预料。支持 readystatechange 事件的每个对象都有一个 readyState 属性,可能包含下列 5 个值中的一个。

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

并非所有对象都会经历 readyState 的这几个阶段。

同时检测交互和完成阶段:

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

由于事件处理程序使用的是匿名函数,因此使用了 arguments.callee 来引用该函数。

(5) pageshow 和 pagehide 事件

Firefox 和 Opera 有一个特性,名叫“往返缓存”(back-forward cache,或 bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了 DOM 和 JavaScript 的状态;实际上是将整个页面都保存在了内存里。

pageshow 事件在页面显示时触发,无论该页面是否来自 bfcache。在重新加载的页面中, pageshow 会在 load 事件触发后触发;而对于 bfcache 中的页面, pageshow 会在页面状态完全恢复的那一刻触发。另外要注意的是,虽然这个事件的目标是 document ,但必须将其事件处理程序添加到 window 。

pageshow 事件的 event 对象还包含一个名为 persisted 的布尔值属性。
如果页面被保存在了 bfcache 中,则这个属性的值为 true ;否则,这个属性的值为 false 。

(function() {
    var showCount = 0;
    EventUtil.addHandler(window, "load", function() {
        alert("Load fired");
    });
    EventUtil.addHandler(window, "pageshow", function() {
        showCount++;
        alert("Show has been fired " + showCount +
            " times. Persisted? " + event.persisted);
    });
})();

通过检测 persisted 属性,就可以根据页面在 bfcache 中的状态来确定是否需要采取其他操作。

与 pageshow 事件对应的是 pagehide 事件,该事件会在浏览器卸载页面的时候触发,而且是在unload 事件之前触发。与 pageshow 事件一样, pagehide 在 document 上面触发,但其事件处理程序必须要添加到 window 对象。这个事件的 event 对象也包含 persisted 属性,不过其用途稍有不同。

对于 pagehide 事件,如果页面在卸载之后会被保存在 bfcache 中,那么 persisted 的值也会被设置为 true 。因此,当第一次触发 pageshow 时, persisted 的值一定是 false。

提示:指定了 onunload 事件处理程序的页面会被自动排除在 bfcache 之外,即使事件处理程序是空的。原因在于, onunload 最常用于撤销在 onload 中所执行的操作,而跳过 onload 后再次显示页面很可能就会导致页面不正常。

(6)hashchange 事件

HTML5 新增了 hashchange 事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。之所以新增这个事件,是因为在 Ajax 应用中,开发人员经常要利用 URL 参数列表来保存状态或导航信息。

必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL 参数列表只要变化就会调用它。此时的 event 对象应该额外包含两个属性: oldURL 和 newURL 。这两个属性分别保存着参数列表变化前后的完整 URL。

EventUtil.addHandler(window, "hashchange", function(event){
    alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
});

只有 Firefox 6+、Chrome 和 Opera 支持 oldURL 和 newURL 属性。为此,最好是使用 location对象来确定当前的参数列表。

EventUtil.addHandler(window, "hashchange", function(event){
    alert("Current hash: " + location.hash);
});

检测浏览器是否支持 hashchange 事件:

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

6、触摸与手势事件

(1)触摸事件

触摸事件会在用户手指放在屏幕上面时、在屏幕上滑动时或从屏幕上移开时触发。

  • touchstart :当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
  • touchmove :当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用 preventDefault()可以阻止滚动。
  • touchend :当手指从屏幕上移开时触发。
  • touchcancel :当系统停止跟踪触摸时触发。

这几个事件都会冒泡,也都可以取消。每个触摸事件的 event 对象都提供了在鼠标事件中常见的属性:bubbles 、 cancelable 、 view 、 clientX 、 clientY 、 screenX 、 screenY 、 detail 、 altKey 、 shiftKey 、 ctrlKeymetaKey

除了常见的 DOM属性外,触摸事件还包含三个用于跟踪触摸的属性。

  • 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>Touch ended (" +
                    event.changedTouches[0].clientX + "," +
                    event.changedTouches[0].clientY + ")";
                break;
            case "touchmove":
                event.preventDefault(); //阻止滚动
                output.innerHTML += "<br>Touch moved (" +
                    event.changedTouches[0].clientX + "," +
                    event.changedTouches[0].clientY + ")";
                break;
        }
    }
}
EventUtil.addHandler(document, "touchstart", handleTouchEvent);
EventUtil.addHandler(document, "touchend", handleTouchEvent);
EventUtil.addHandler(document, "touchmove", handleTouchEvent);

(2)手势事件

当两个手指触摸屏幕时就会产生手势,手势通常会改变显示项的大小,或者旋转显示项。有三个手势事件:

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

只有两个手指都触摸到事件的接收容器时才会触发这些事件。

触摸事件和手势事件之间存在某种关系。当一个手指放在屏幕上时,会触发 touchstart 事件。如果另一个手指又放在了屏幕上,则会先触发 gesturestart 事件,随后触发基于该手指的 touchstart事件。如果一个或两个手指在屏幕上滑动,将会触发 gesturechange 事件。但只要有一个手指移开,就会触发 gestureend 事件,紧接着又会触发基于该手指的 touchend 事件。

与触摸事件一样,每个手势事件的 event 对象都包含着标准的鼠标事件属性: bubbles 、cancelable 、 view 、 clientX 、 clientY 、 screenX 、 screenY 、 detail 、 altKey 、 shiftKey 、ctrlKeymetaKey

还包含两个额外的属性: rotation 和 scale 。其中, rotation 属性表
示手指变化引起的旋转角度,负值表示逆时针旋转,正值表示顺时针旋转(该值从 0 开始)。而 scale属性表示两个手指间距离的变化情况(例如向内收缩会缩短距离);这个值从 1 开始,并随距离拉大而增长,随距离缩短而减小。

使用手势事件的一个示例:

function handleGestureEvent(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 ended (rotation=" + event.rotation +
                ",scale=" + event.scale + ")";
            break;
        case "gesturechange":
            output.innerHTML += "<br>Gesture changed (rotation=" + event.rotation +
                ",scale=" + event.scale + ")";
            break;
    }
}
document.addEventListener("gesturestart", handleGestureEvent, false);
document.addEventListener("gestureend", handleGestureEvent, false);
document.addEventListener("gesturechange", handleGestureEvent, false);

五、内存和性能

在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。导致这一问题的原因是多方面的。首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的 DOM访问次数,会延迟整个页面的交互就绪时间。

1、事件委托

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>

使用事件委托,只需在DOM 树中尽量最高的层次上添加一个事件处理程序:

var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    switch (target.id) {
        case "doSomething":
            document.title = "I changed the document's title";
            break;
        case "goSomewhere":
            location.href = "http://www.wrox.com";
            break;
        case "sayHi":
            alert("hi");
            break;
    }
});

优点:

  • 在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的 DOM引用更少,所花的时间也更少。
  • 整个页面占用的内存空间更少,能够提升整体性能。

最适合采用事件委托技术的事件包括 click 、 mousedown 、 mouseup 、 keydown 、 keyupkeypress

2、移除事件处理程序

每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢。

内存中留有那些过时不用的“空事件处理程序”(dangling event handler),也是造成 Web 应用程序内存与性能问题的主要原因。

如果你知道某个元素即将被移除,那么最好手工移除事件处理程序:

<div id="myDiv">
    <input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function() {
    //先执行某些操作
    btn.onclick = null; // 移除事件处理程序
    document.getElementById("myDiv").innerHTML = "Processing...";
};
</script>

注意,在事件处理程序中删除按钮也能阻止事件冒泡。目标元素在文档中是事件冒泡的前提。

在页面卸载之前,先通过 onunload 事件处理程序移除所有事件处理程序。只要是通过 onload 事件处理程序添加的东西,最后都要通过 onunload 事件处理程序将它们移除。

六、模拟事件

事件,就是网页中某个特别值得关注的瞬间。事件经常由用户操作或通过其他浏览器功能来触发。

1、DOM中的事件模拟

可以在 document 对象上使用 createEvent() 方法创建 event 对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。

在创建了 event 对象之后,还需要使用与事件有关的信息对其进行初始化。每种类型的 event 对象都有一个特殊的方法,为它传入适当的数据就可以初始化该 event 对象。不同类型的这个方法的名字也不相同,具体要取决于 createEvent() 中使用的参数。

模拟事件的最后一步就是触发事件。这一步需要使用 dispatchEvent() 方法,所有支持事件的DOM 节点都支持这个方法。调用 dispatchEvent() 方法时,需要传入一个参数,即表示要触发事件的 event 对象。触发事件之后,该事件就跻身“官方事件”之列了,因而能够照样冒泡并引发相应事
件处理程序的执行。

模拟鼠标事件

创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是为 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时使用

前 4 个参数对正确地激发事件至关重要,因为浏览器要用到这些参数;

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);

同样,对于键盘事件、IE中的事件模拟和其他事件也可以模拟,也可以自定义 DOM 事件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,426评论 1 11
  • 事件是什么,可以用来做什么,什么时候用到它? 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。JavaScr...
    茂茂爱吃鱼阅读 1,480评论 0 16
  • 第13章 事件 1. 事件流 事件流描述的是从页面中接收事件的顺序。 (1) 事件冒泡 IE 的事件流叫做事件冒泡...
    yinxmm阅读 912评论 0 17
  • JavaScript 程序采用了异步事件驱动编程模型。在这种程序设计风格下,当文档、浏览器、元素或与之相关的对象发...
    劼哥stone阅读 1,232评论 3 11
  • JavaScript和HTML的交互是通过事件实现的。 事件就是用户或浏览器自身执行的某种动作。 举几个可能发生的...
    饥人谷_Tom阅读 348评论 0 0