DOM —— 事件

事件流

JavaScript與HTML之間的交互是通過事件實(shí)現(xiàn)的窿克。事件骏庸,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬間毛甲。可以使用偵聽器(或處理程序)來預(yù)定事件具被,以便事件發(fā)生時(shí)執(zhí)行相應(yīng)的代碼玻募。這種在傳統(tǒng)軟件工程中被成為觀察員模式的模型,支持頁(yè)面的行為(js代碼)與頁(yè)面的外觀(HTML和CSS代碼)之間的松散耦合一姿。

事件最早是在IE3和Netscape Navigator2(以下簡(jiǎn)稱網(wǎng)景)中出現(xiàn)的补箍,當(dāng)時(shí)作為分擔(dān)服務(wù)器運(yùn)算負(fù)載的一種手段。在IE4和網(wǎng)景4發(fā)布時(shí)啸蜜,這兩種瀏覽器都提供了相似不相同的API,這些API并存經(jīng)過了好幾個(gè)主要版本辈挂,DOM2級(jí)規(guī)范開始嘗試以一種符合邏輯的方式來標(biāo)準(zhǔn)化DOM事件衬横。IE9、Firefox终蒂、Opera蜂林、Safari和Chrome全部已實(shí)現(xiàn)了DOM2級(jí)事件模塊的核心部分。IE8是最后一個(gè)仍然使用其專有事件系統(tǒng)的主要瀏覽器拇泣。

定義與由來
當(dāng)瀏覽器發(fā)展到第四代時(shí)噪叙,瀏覽器開發(fā)團(tuán)隊(duì)遇到了一個(gè)很有意思的問題:頁(yè)面的哪一部分會(huì)擁有某個(gè)特定的事件?想象一下霉翔,在一張紙上畫一個(gè)同心圓睁蕾,如果你把手指放在圓心上,那么你的手指指向的不是一個(gè)圓债朵,而是紙上所有的圓子眶。兩家公司的瀏覽器開發(fā)團(tuán)隊(duì)看待瀏覽器事件方面還是一致的。如果你單擊了某個(gè)按鈕序芦,他們都認(rèn)為單擊事件不僅僅發(fā)生在按鈕上臭杰。換句話說,在單擊按鈕的同時(shí)谚中,你也單擊了按鈕的容器元素渴杆,甚至也單擊了整個(gè)頁(yè)面。
事件流描述的是從頁(yè)面中接受事件的順序宪塔。但有意思的是磁奖,IE和網(wǎng)景開發(fā)團(tuán)隊(duì)居然提出了差不多完全相反的事件流的概念。IE的事件流是事件冒泡某筐,而網(wǎng)景的事件流是事件捕獲流点寥。


事件冒泡

IE的事件流叫做事件冒泡(event bubbling),即事件開始時(shí)由最具體的元素(文檔中嵌套層次最深的那個(gè)節(jié)點(diǎn))接收来吩,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)(文檔)敢辩。以下面的HTML頁(yè)面為例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Event Bubbling Example</title>
</head>
<body>
    <div id="myDiv">Click Me</div>
</body>
</html>

如果單擊了頁(yè)面中的<div>元素蔽莱,那么這個(gè)click事件會(huì)按照如下順序傳播:

  1. <div>
  2. <body>
  3. <html>
  4. document

也就是說,click事件首先在<div>元素上發(fā)生戚长,而這個(gè)元素就是我們單擊的元素盗冷。然后,click事件沿DOM數(shù)向上傳播同廉,在每一級(jí)節(jié)點(diǎn)上都會(huì)發(fā)生仪糖,直至傳播到document對(duì)象。


事件冒泡流

所有瀏覽器都支持事件冒泡迫肖,但在具體實(shí)現(xiàn)上還是有一些差別锅劝。IE5.5及更早版本會(huì)跳過<html>元素直接到document對(duì)象。IE9蟆湖、Chrome故爵、Safari則將事件一直冒泡到window對(duì)象。


事件捕獲

網(wǎng)景團(tuán)隊(duì)提出的另一種事件流叫做事件捕獲(event capturing)隅津。事件捕獲的思想是不太具體的節(jié)點(diǎn)應(yīng)該更早接收到事件诬垂,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件。事件捕獲的用意在于在事件到達(dá)預(yù)定目標(biāo)之前捕獲它伦仍。如果仍以之前HTML代碼演示捕獲例子结窘,那么單擊click元素就會(huì)以下列順序觸發(fā)click事件:

  1. document
  2. <html>
  3. <body>
  4. <div>

在事件捕獲過程中,document對(duì)象首先接收到click事件充蓝,然后事件沿DOM數(shù)依次向下隧枫,一直傳播到事件具體目標(biāo),即<div>元素谓苟。

事件捕獲

雖然事件捕獲是網(wǎng)景唯一支持的事件流模型悠垛,但I(xiàn)E9、Safari娜谊、Chrome确买、Opera和Firefox目前也都支持這種事件流模型。盡管”DOM2級(jí)事件“規(guī)范要求事件應(yīng)該從document對(duì)象開始傳播纱皆,但這些瀏覽器都是從window對(duì)象開始捕獲事件的湾趾。
由于老版本瀏覽器不支持,很少有人使用事件捕獲派草,一般都使用事件冒泡搀缠。


DOM事件流

DOM2級(jí)事件規(guī)定的事件流包括三個(gè)階段:事件捕獲階段、處于目標(biāo)階段近迁、事件冒泡階段艺普。首先發(fā)生的是事件捕獲,為截獲事件提供了機(jī)會(huì)。然后是實(shí)際的目標(biāo)接收到事件歧譬。最后一個(gè)階段是冒泡階段岸浑,可以在這個(gè)階段對(duì)事件做出響應(yīng)。以前面簡(jiǎn)單的HTML頁(yè)面為例瑰步,單擊<div>元素會(huì)按照下圖所示順序觸發(fā)事件矢洲。


DOM事件流

在DOM事件流中,實(shí)際的目標(biāo)<div>元素在捕獲階段不會(huì)接收到事件缩焦。這意味在捕獲階段读虏,事件從document到<html>再到<body>后就停止了。下一個(gè)階段是”處于目標(biāo)“階段袁滥,于是事件在<div>上發(fā)生盖桥,并在事件處理中被看成冒泡階段的一部分星岗。然后芙委,冒泡階段發(fā)生妖爷,事件又傳播回文檔悯辙。

IE8及更早版本不支持DOM事件流。


事件處理程序

事件就是用戶或?yàn)g覽器自身執(zhí)行的某種動(dòng)作穿香。諸如:click、load和mouseover,都是事件的名字猾普。而響應(yīng)某個(gè)個(gè)事件的函數(shù)叫做事件處理程序(或事件偵聽器)。

其實(shí)JS與HTML的交互就是事件處理程序執(zhí)行的結(jié)果本谜。

事件處理程序的名字以"on"開頭初家,因此click事件的事件處理程序(click事件偵聽器)就是onclick,load事件的事件處理程序(load事件偵聽器)就是onload乌助。

為事件指定處理程序的方式有好幾種(面試)


HTML事件處理程序

某個(gè)元素支持的每種事件溜在,都可以使用一個(gè)與相應(yīng)事件處理程序同名的HTML特性來指定。這個(gè)特性的值應(yīng)該是能夠執(zhí)行的JavaScript代碼他托。如:

    <input type="button" value="Click Me" onclick="alert('Clicked')">

當(dāng)單擊這個(gè)按鈕時(shí)掖肋,就會(huì)顯示一個(gè)警告框。這個(gè)操作是通過指定onclick特性一些JavaScript代碼作為它的值來定義的赏参。由于這個(gè)值是JavaScript志笼,因此不能在其中使用未經(jīng)轉(zhuǎn)義的HTML語法字符。為了避免使用HTML實(shí)體把篓,這里使用單引號(hào)纫溃,如果想要使用雙引號(hào),可以這樣改寫:

    <input type="button" value="Click Me" onclick="alert(&quot;Clicked&quot;)">

在HTML中定義的事件處理程序可以包含要執(zhí)行的具體動(dòng)作韧掩,也可以調(diào)用在頁(yè)面其他地方定義的腳本:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Bubbling Example</title>
    <script src="./js/fuck.js"></script>
</head>
<body>
    <input type="button" value="Click Me" onclick="showMessage()">
    <script>
        function showMessage() {
            alert("hello world");
        }       
    </script>
</body>
</html>

單擊按鈕調(diào)用showMessage()函數(shù)紊浩,這個(gè)函數(shù)是在一個(gè)獨(dú)立<script>元素中定義的,當(dāng)然也可以被包含在一個(gè)外部文件中。事件處理程序中的代碼在執(zhí)行時(shí)坊谁,有權(quán)訪問全局作用域中任何代碼费彼。

這樣指定事件處理程序具有一些獨(dú)到之處。首先呜袁,這樣會(huì)創(chuàng)建一個(gè)封裝著元素屬性值的函數(shù)敌买。這個(gè)函數(shù)中有一個(gè)局部變量event,也就是事件對(duì)象:

    <input type="button" value="Click Me" onclick="console.log(event.type)">    
    <!--    輸出click    -->

event為事件對(duì)象阶界,我們打印出來看看里面有啥

    <input type="button" value="Click Me" onclick="console.log(event)">
null: MouseEvent {isTrusted: true, screenX: 261, screenY: 236, clientX: 38, clientY: 17, …}
altKey: false
bubbles: true
button: 0
buttons: 0
cancelable: true
cancelBubble: false
clientX: 38
clientY: 17
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 1
eventPhase: 0
fromElement: null
isTrusted: true
layerX: 38
layerY: 17
metaKey: false
movementX: 0
movementY: 0
offsetX: 28
offsetY: 5
pageX: 38
pageY: 17
path: Array(5) [input, body, html, …]
relatedTarget: null
returnValue: true
screenX: 261
screenY: 236
shiftKey: false
sourceCapabilities: InputDeviceCapabilities {firesTouchEvents: false}
srcElement: input
target: input
timeStamp: 3469.8000000207685
toElement: input
type: "click"
view: Window {postMessage: , blur: , focus: , …}
which: 1
x: 38
y: 17
__proto__: MouseEvent {screenX: <accessor>, screenY: <accessor>, clientX: <accessor>, …}

通過event變量虹钮,可以直接訪問事件對(duì)象,你不用自己定義它膘融,也不用從函數(shù)的參數(shù)列表中讀取芙粱。在這個(gè)函數(shù)內(nèi)部,this值等于事件的目標(biāo)元素氧映。如:

    <input type="button" value="Click Me" onclick="console.log(this.value)">    
    <!--    輸出 "Click Me"-->

關(guān)于這個(gè)動(dòng)態(tài)創(chuàng)建的函數(shù)春畔,另一個(gè)有意思的地方是它擴(kuò)展作用域的方式,在這個(gè)函數(shù)內(nèi)部岛都,可以像訪問局部變量一樣訪問document及該元素本身的成員律姨。這個(gè)函數(shù)使用with像下面這樣擴(kuò)展作用域:

        function() {
            with(document) {
                with(this) {
                    // 元素屬性值
                }
            }
        }

這樣一來,事件處理程序要訪問自己的屬性就容易多了臼疫。

    <input type="button" value="Click Me" onclick="alert(value)">   
    <!--    輸出 "Click Me"    -->
總結(jié)(面試):

這種在HTML中指定事件處理程序有兩個(gè)缺點(diǎn)择份。

時(shí)差問題

用戶可能會(huì)在HTML元素一出現(xiàn)在頁(yè)面上就觸發(fā)相應(yīng)的事件,但當(dāng)時(shí)的事件處理程序有可能尚不具備執(zhí)行條件烫堤。
比如荣赶,將click事件處理函數(shù)放在HTML下方,頁(yè)面最底部鸽斟,用戶在函數(shù)解析完成前激活了click事件拔创,就會(huì)引發(fā)錯(cuò)誤。為此富蓄,很多HTML事件處理程序都會(huì)被封裝在一個(gè)try-catch塊中剩燥,以便錯(cuò)誤不會(huì)浮出水面,如:

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

這樣立倍,如果在showMessage()函數(shù)有定義之前單擊按鈕躏吊,用戶不會(huì)看到JavaScript錯(cuò)誤,因?yàn)樵跒g覽器有機(jī)會(huì)處理錯(cuò)誤之前帐萎,錯(cuò)誤就被捕獲了比伏。

作用域問題

另一個(gè)缺點(diǎn)是,這樣擴(kuò)展事件處理程序的作用域鏈在不同瀏覽器導(dǎo)致不同結(jié)果疆导。不同JavaScript引擎遵循的標(biāo)識(shí)符規(guī)則略有差異赁项,很可能會(huì)在訪問非限定對(duì)象成員時(shí)出錯(cuò)。

分離原則

通過HTML指定事件處理程序最后一個(gè)缺點(diǎn)是HTML與JavaScript代碼緊密耦合。如果要更換事件處理程序悠菜,就要改動(dòng)HTML代碼和JavaScript代碼舰攒,而這正是開發(fā)人員摒棄HTML事件處理程序,轉(zhuǎn)而使用JavaScript指定事件處理程序的原因所在悔醋。

不要使用HTML指定事件處理程序

DOM0級(jí)事件處理程序

通過JavaScript指定事件處理方式的傳統(tǒng)方式摩窃,就是將一個(gè)函數(shù)賦值給一個(gè)事件處理程序?qū)傩浴_@種為事件處理程序賦值的方法是在第四代Web瀏覽器中出現(xiàn)芬骄。

  • 簡(jiǎn)單
  • 具有跨瀏覽器優(yōu)勢(shì)

每個(gè)元素(包括window和document)都有自己的事件處理程序?qū)傩曰福@些屬性通常全部小寫,例如onclick账阻。將這種屬性的值設(shè)置為一個(gè)函數(shù)蒂秘,就可以指定事件處理程序。

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

在此淘太,我們通過文檔對(duì)象取得了一個(gè)按鈕的引用姻僧,然后為它指定了onclick事件處理程序。但要注意蒲牧,在這些代碼運(yùn)行以前不會(huì)指定事件處理程序撇贺,因此如果這些代碼在頁(yè)面中位于按鈕后面,就有可能在一段時(shí)間內(nèi)怎么單擊都沒有反應(yīng)冰抢。

使用DOM0級(jí)方法指定的事件處理程序被認(rèn)為是元素的方法松嘶,因此,這時(shí)候的事件處理程序是在元素的作用域中運(yùn)行晒屎;換句話說喘蟆,程序中的this引用當(dāng)前元素缓升。

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

單擊按鈕顯示的是元素的ID鼓鲁,這個(gè)ID是通過this.id取得的。不僅僅是ID港谊,實(shí)際上可以在事件處理程序中通過this訪問元素的任何屬性和方法骇吭。
以這種方式添加的事件處理程序會(huì)在事件流的冒泡階段被處理。

也可以刪除通過DOM0級(jí)方法指定的事件處理程序歧寺。

        btn.onclick = null;    // 刪除事件處理程序

此時(shí)單擊按鈕不會(huì)有任何動(dòng)作發(fā)生燥狰。

個(gè)人理解:沒有動(dòng)作發(fā)生因?yàn)闆]有事件處理程序,但是的確存在這個(gè)事件被觸發(fā)斜筐。只是我們沒有對(duì)這個(gè)事件發(fā)生時(shí)“做些什么”而已龙致。

如果你使用HTML指定事件處理程序,那么onclick屬性的值就是一個(gè)包含著在同名HTML特性中指定的代碼的函數(shù)顷链。而將相應(yīng)的屬性設(shè)置為null目代,也可以刪除以這種方式指定的事件e處理程序。


DOM2級(jí)事件處理程序

"DOM2級(jí)事件"定義了兩個(gè)方法,用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()榛了。所有DOM節(jié)點(diǎn)中都包含這兩個(gè)方法在讶,并且它們都接受3個(gè)參數(shù):要處理的事件名、作為事件處理程序的函數(shù)和一個(gè)布爾值霜大。最后這個(gè)布爾值參數(shù)如果是true构哺,表示在捕獲階段調(diào)用事件處理程序;如果是false战坤,表示在冒泡階段調(diào)用事件處理程序曙强。

按鈕上為click事件添加事件處理程序:

    <input type="button" id="myBtn" value="Click Me">
        var btn = document.getElementById("myBtn");
        btn.addEventListener("click", function () {
            alert(this.id);
        }, false);

上面的代碼為一個(gè)按鈕添加了onclick事件處理程序,而且該事件會(huì)在冒泡階段被觸發(fā)(因?yàn)樽詈笠粋€(gè)參數(shù)false)湖笨。與DOM0級(jí)方法一樣旗扑,這里添加的事件處理程序也是在其依附的元素的作用域中運(yùn)行。使用DOM2級(jí)方法添加事件處理程序的主要好處是可以添加多個(gè)事件處理程序慈省。

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

調(diào)用的事件處理程序會(huì)按照添加它們的順序觸發(fā)臀防,因此首先會(huì)顯示ID,而后顯示”Hello World!“消息边败。
通過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除袱衷。

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

這樣行嗎?當(dāng)然不行笑窜,兩個(gè)方法定義的事件處理函數(shù)根本就不是”一個(gè)東西“致燥,即它們是兩個(gè)不相干的函數(shù)對(duì)象。

我們需要使用函數(shù)表達(dá)式排截。

        var btn = document.getElementById("myBtn");

        var handler = function() {
            alert(this.id);
        };

        btn.addEventListener("click",handler,false);
        btn.removeEventListener("click",handler,false);

大多數(shù)情況嫌蚤,都是將事件處理程序添加到事件流的冒泡階段,這樣可以最大限度的兼容各種瀏覽器断傲。
不是特別需要脱吱,不建議在事件捕獲階段注冊(cè)事件處理程序。


IE事件處理程序(IE兼容方法)

IE實(shí)現(xiàn)了與DOM中類似的兩個(gè)方法:attachEvent()detachEvent()
這兩個(gè)方法接受相同的兩個(gè)參數(shù):事件處理程序名稱和事件處理函數(shù)认罩。由于IE8及更早版本只支持事件冒泡箱蝠,所以通過attachEvent()添加的事件處理程序都會(huì)被添加到冒泡階段。
使用attachEvent()為按鈕添加一個(gè)事件處理程序:

        btn.attachEvent("onclick",function() {
            alert("Clicked");
        });

注意垦垂,參數(shù)從"click"變?yōu)榱?onclick"宦搬。

IE中使用attachEvent()與使用DOM0級(jí)方法的主要區(qū)別在于事件處理程序的作用域。在使用DOM0級(jí)方法的情況下劫拗,事件處理程序會(huì)在其所屬元素的作用域內(nèi)運(yùn)行间校;在使用attachEvent()方法的情況下,事件處理程序會(huì)在全局作用域下與西寧页慷,因此this等于window憔足。

        btn.attachEvent("onclick",function() {
            alert(this === window);
        });

在編寫跨瀏覽器的代碼時(shí)聂渊,記住。
與addEventListener()類似四瘫,attachEvent()方法也可以用來為一個(gè)元素添加多個(gè)事件處理程序汉嗽。

        btn.attachEvent("onclick",function() {
            alert(this === window);
        });
        btn.attachEvent("onclick",function() {
            alert("Hello World!");
        });

但是!這些事件處理程序不是以添加它們的順序來執(zhí)行的找蜜,而是以相反的順序被觸發(fā)
先是看到Hello World!饼暑,然后才是true。

使用detachEvent()移除事件處理程序和removeEventListener()是差不多的洗做。

        var btn = document.getElementById("myBtn");

        var handler = function() {
            alert("hello world!")
        }       
        btn.attachEvent("onclick",handler);
        btn.detachEvent("onclick",handler);

支持IE事件處理程序的瀏覽器有IE和Opera


跨瀏覽器的事件處理程序

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

這連個(gè)方法都會(huì)檢測(cè)傳入元素是否存在DOM2級(jí)方法弓叛。如果存在,使用該方法:傳入事件類型诚纸、事件處理程序函數(shù)和第三個(gè)參數(shù)false(表示冒泡階段)撰筷。如果存在的是IE的方法,則采取第二種方案畦徘。
為了在IE8級(jí)更早版本中運(yùn)行毕籽,此時(shí)的事件類型必須加上"on"前綴。
最后一種可能是使用DOM0級(jí)方法(在現(xiàn)在瀏覽器中井辆,不會(huì)執(zhí)行這里的代碼)关筒。此時(shí),我們使用的是方括號(hào)語法來講屬性名指定為事件處理程序杯缺,或者將屬性設(shè)置為null蒸播。

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

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

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

addHandler()和removeHandler()沒有考慮所有的瀏覽器問題,例如在IE中的作用域問題萍肆,不過袍榆,使用它們添加和移除事件處理程序還是足夠了。
此外要注意塘揣,DOM0級(jí)對(duì)每個(gè)事件只支持一個(gè)事件處理程序包雀。不過現(xiàn)在只支持DOM0級(jí)的瀏覽器應(yīng)該很少了。


事件對(duì)象

在觸發(fā)DOM上的事件時(shí)勿负,會(huì)產(chǎn)生一個(gè)事件對(duì)象event馏艾,這個(gè)對(duì)象中包含所有與事件有關(guān)的信息劳曹。包活導(dǎo)致事件的元素奴愉、事件的類型及其他與特定事件相關(guān)的信息。例如铁孵,鼠標(biāo)操作導(dǎo)致的事件對(duì)象中锭硼,會(huì)包含鼠標(biāo)位置的信息,鍵盤操作導(dǎo)致的事件對(duì)象中蜕劝,會(huì)包含與按下的鍵有關(guān)的信息檀头。
所有的瀏覽器都支持event對(duì)象轰异,但支持方式不同。

DOM中的事件對(duì)象

兼容DOM的瀏覽器會(huì)將一個(gè)event對(duì)象傳入到事件處理程序中暑始。無論指定事件處理程序時(shí)使用什么方法(DOM0級(jí)或DOM2級(jí))搭独,都會(huì)傳入event對(duì)象。

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

event屬性始終都會(huì)包含被觸發(fā)的事件類型廊镜,例如"click"牙肝。
在通過HTM特性指定事件處理程序時(shí),變量event中保存著event對(duì)象嗤朴。

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

以這種方式提供event對(duì)象配椭,可以讓HTML特性事件處理程序與JavaScript函數(shù)執(zhí)行相同的操作。
event對(duì)象包含與創(chuàng)建它的特定事件有關(guān)的屬性和方法雹姊。觸發(fā)的事件類型不一樣股缸,可用的屬性和方法也不一樣。不過所有屬性都會(huì)有一些共有的成員吱雏。

        /*
        
        屬性/方法                       類型              讀/寫                 說明

        bubbles                       Boolean            只讀             表明事件是否冒泡

        cancelable                    Boolean            只讀             表明是否可以取消事件的默認(rèn)行為

        currentTarget                 Element            只讀             其事件處理程序當(dāng)前正在處理事件的那個(gè)元素
        
        defaultPrevented              Boolean            只讀             為true表示已經(jīng)調(diào)用了preventDefault()

        detail                        Integer            只讀             與事件有關(guān)的細(xì)節(jié)信息

        eventPhase                    Integer            只讀             調(diào)用事件處理程序的階段:1捕獲階段敦姻、2"處于目標(biāo)"、3表示冒泡階段

        preventDefault                Function           只讀             取消事件的默認(rèn)行為歧杏。如果cancleable是true替劈,則可以使用這個(gè)方法

        stopImmediatePropagation()    Function           只讀             取消事件的進(jìn)一步捕獲或冒泡,同時(shí)阻止任何事件處理程序被調(diào)用

        stopPropagation()             Function           只讀             取消事件的進(jìn)一步捕獲或冒泡得滤。如果bubbles為true陨献,則可以使用這個(gè)方法

        target                        Element            只讀             事件的目標(biāo)

        trusted                       Boolean            只讀             為true表示目標(biāo)是瀏覽器生成的。為false表示事件是由開發(fā)人員通過JavaScript創(chuàng)建的

        type                          String             只讀             被觸發(fā)的事件的類型

        view                          AbstractView       只讀             與事件關(guān)聯(lián)的抽象視圖懂更。等同于發(fā)生事件的window對(duì)象眨业。

        */

在事件處理程序內(nèi)部,對(duì)象this始終等于cureentTarget的值沮协,而target則只包含事件的實(shí)際目標(biāo)龄捡。

        var btn = document.getElementById("myBtn");
        btn.onclick = function(event) {
            alert(event.currentTarget === this);    // true
            alert(event.target === this);           // true
        }

這個(gè)例子檢測(cè)了currentTarget和target與this的值。由于click事件的目標(biāo)是按鈕慷暂,因此這三個(gè)值是相等的聘殖。
如果事件處理程序存在于按鈕的父節(jié)點(diǎn)中(例如document.body),那么情況就有所變化行瑞。

        document.body.onclick = function(event) {
            alert(event.currentTarget === document.body);                   // true
            alert(this === document.body);                                  // true
            alert(event.target === document.getElementById("myBtn"));       // true
        }

當(dāng)單擊這個(gè)例子中的按鈕時(shí)奸腺,this和currentTarget都等于document.body,因此事件處理程序是注冊(cè)到這個(gè)元素上的血久。然而突照,target元素卻等于按鈕元素,因?yàn)樗莄lick事件真正的目標(biāo)(用戶操作點(diǎn)擊了按鈕)氧吐。只是按鈕上沒有事件處理程序讹蘑,沒喲函數(shù)執(zhí)行末盔。結(jié)果click事件冒泡到了body,在那里事件得到處理座慰。

在需要通過一個(gè)函數(shù)處理多個(gè)事件時(shí)陨舱,可以使用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 "mouseouot":
                event.target.style.backgroundColor = "";
                break;
            }
        };

        btn.onclick = handler;
        btn.onmouseover = handler;
        btn.onmouseout = handler;

例子定義了名為handler的函數(shù)版仔,用于處理三種事件:click隅忿、mouseover、mouseout邦尊。
當(dāng)單擊按鈕時(shí)背桐,出現(xiàn)一個(gè)警告框。當(dāng)按鈕移動(dòng)到按鈕上面時(shí)蝉揍,背景顏色變化成紅色链峭。當(dāng)鼠標(biāo)移動(dòng)出按鈕時(shí),背景顏色回復(fù)默認(rèn)值又沾。

這里通過檢測(cè)event.type屬性弊仪,讓函數(shù)能夠確定發(fā)生了什么事件,并執(zhí)行相應(yīng)操作杖刷。

要阻止特定事件的默認(rèn)行為励饵,可以使用preventDefault()方法。例如滑燃,鏈接的默認(rèn)行為就是在被單擊時(shí)導(dǎo)航到其href指定的URL役听。如果想阻止鏈接導(dǎo)航這一默認(rèn)行為,那么通過onclick事件處理程序可以取消它表窘。

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

另外只有cancelable屬性設(shè)置為true的事件典予,才可以使用preventDefault()來取消去默認(rèn)行為。
另外乐严,stopPropagation()方法用于立即停止事件在DOM層次中的傳播瘤袖,即取消進(jìn)一步的事件捕獲或冒泡。
例如昂验,直接添加到一個(gè)按鈕的事件處理程序可以調(diào)用stopPropagation()捂敌,從而避免觸發(fā)注冊(cè)在document.body上面的事件處理程序。

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

        document.body.onclick = function(event) {
            alert("Body clicked");
        }

事件在目標(biāo)階段被觸發(fā)后既琴,不會(huì)傳播到document.body占婉,因此就不會(huì)觸發(fā)注冊(cè)在這個(gè)元素上的onclick事件處理對(duì)象。
事件對(duì)象的eventPhase屬性呛梆,可以用來確定事件當(dāng)前位于事件流的哪個(gè)階段锐涯。

  • 捕獲階段:1
  • 目標(biāo)階段:2
  • 冒泡階段:3
        var btn = document.getElementById("myBtn");
        btn.onclick = function(event) {
            console.log(event.eventPhase);      // 1
        }
        
        document.body.addEventListener("click",function(event) {
            console.log(event.eventPhase);
        },true);                            // 2

        document.body.onclick = function(event) {
            console.log(event.eventPhase);
        };                                  // 3

首先執(zhí)行的事件處理程序是在捕獲階段觸發(fā)的添加到document.body的那一個(gè)磕诊,結(jié)果會(huì)彈出一個(gè)警告框顯示表示eventPhase的1填物。接著纹腌,會(huì)觸發(fā)在按鈕上注冊(cè)的事件處理程序,此時(shí)的eventPhase值為2滞磺。最后一個(gè)被觸發(fā)的事件處理程序升薯,是在冒泡階段執(zhí)行的添加到document.body上的那一個(gè),顯示eventPhase的值為3击困。
當(dāng)eventPhase等于2時(shí)涎劈,this、target阅茶、currentTarget始終相等蛛枚。

只有事件處理程序執(zhí)行期間,event對(duì)象才會(huì)存在脸哀;一旦事件處理程序執(zhí)行完成蹦浦,event就會(huì)銷毀。


IE中的事件對(duì)象

與訪問DOM中的event對(duì)象不同撞蜂,要訪問IE中的event對(duì)象有幾種不同方式盲镶,取決與執(zhí)行事件處理程序的方法。在使用DOM0級(jí)方法添加事件處理程序時(shí)蝌诡,event對(duì)象作為window對(duì)象的一個(gè)屬性存在溉贿。

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

在此,我們通過window.event取得了event對(duì)象浦旱,并檢測(cè)了被觸發(fā)事件的類型宇色。
如果使用attachEvent()添加的,那么就會(huì)有一個(gè)event對(duì)象作為參數(shù)被傳入事件處理程中颁湖。

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

如果是通過HTML特性指定:

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

IE的event對(duì)象同樣也包含與創(chuàng)建它的事件相關(guān)的屬性和方法代兵。其中很多屬性和方法都有對(duì)應(yīng)的或者相關(guān)的DOM屬性和方法。與DOM的event對(duì)象一樣爷狈,這些屬性和方法也會(huì)因?yàn)槭录愋偷牟煌煌灿埃惺录?duì)象都有這些:

    /*
        
        屬性/方法                       類型              讀/寫                 說明
        
        cancelBubble                   Boolean           讀/寫            默認(rèn)值false,將其設(shè)置為true可以取消事件冒泡

        returnValue                    Boolean           讀/寫            默認(rèn)值為true涎永,將其設(shè)置為false可以取消事件的默認(rèn)行為

        srcElement                     Element           只讀             事件的目標(biāo)

        type                           String            只讀             被觸發(fā)的事件的類型   

    /*

因?yàn)槭录幚沓绦虻淖饔糜蚴歉鶕?jù)它的方式來確定的思币,所以不能認(rèn)為this會(huì)始終等于事件目標(biāo)。故而羡微,最好還是使用event.srcElement比較保險(xiǎn)谷饿。

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

        btn.attachEvent("onclick",function(event) {
            alert(event.srcElement === this);           // false
        });

在第一個(gè)事件處理程序中(使用DOM0級(jí)方法),srcElement屬性等于this妈倔,但在第二個(gè)事件處理程序中博投,這兩者的值不同。
returnValue屬性相當(dāng)于DOM中的preventDefault()方法盯蝴,它們的作用都是取消給定事件的默認(rèn)行為毅哗,只要將returnValue設(shè)置為false听怕,就可以阻止默認(rèn)行為。

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

相應(yīng)的虑绵,cancelBubbles屬性與DOM中的stopPropagation()方法相同尿瞭,都是用來停止事件冒泡的。由于IE不支持事件捕獲翅睛,因?yàn)橹荒苋∠录芭萆椋坏玸topPropagation()可以同時(shí)取消事件捕獲和冒泡。例如:

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

        document.body.onclick = function() {
            alert("Body clicked");
        };

跨瀏覽器事件對(duì)象

雖然DOM和IE中的event對(duì)象不同捕发,但基于它們之間的相似性依舊可以拿出跨瀏覽器的方案來疏旨。
IE中event對(duì)象的全部信息和方法DOM對(duì)象中都有,只不過實(shí)現(xiàn)方式不一樣扎酷。

        var EventUtil = {
            addHandler: function (element, type, handler) {     // 跨瀏覽器添加事件處理程序
                // 省略
            },

            getEvent: function (event) {                        // 跨瀏覽器得到事件對(duì)象
                return event ? event : window.event;
            },

            getTarget: function (event) {                       // 跨瀏覽器得到事件目標(biāo) 
                return event.target || event.srcElement;
            },

            preventDefault: function (event) {                  // 跨瀏覽器阻止事件傳播(IE為取消事件冒泡)
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            },

            removeHandler: function (element, type, handler) {  // 跨瀏覽器移除事件處理程序
                // 省略
            },

            stopPropagation: function (event) {                 // 跨瀏覽器組織默認(rèn)行為
                if (event.stopPropagation) {
                    event.stopPropagation();
                } else {
                    event.cancelBubble = true;
                }
            }
        };

事件類型

Web瀏覽器中可能發(fā)生的事件有很多類型充石。不同的事件類型具有不同的信息,而”DOM3及事件“規(guī)定了以下幾類事件霞玄。

  • UI(User Interface)事件骤铃,當(dāng)用戶與頁(yè)面上的元素交互時(shí)觸發(fā)榨呆;
  • 焦點(diǎn)事件绿聘,當(dāng)元素獲得或失去焦點(diǎn)時(shí)觸發(fā);
  • 鼠標(biāo)事件辜王,當(dāng)用戶通過鼠標(biāo)在頁(yè)面上執(zhí)行操作時(shí)觸發(fā)惫企;
  • 滾輪事件撕瞧,當(dāng)使用鼠標(biāo)(或類似設(shè)備)時(shí)觸發(fā);
  • 文本事件狞尔,當(dāng)在文檔中輸入文本時(shí)觸發(fā)丛版;
  • 鍵盤事件,當(dāng)用戶通過鍵盤在頁(yè)面上執(zhí)行操作時(shí)觸發(fā)偏序;
  • 合成事件页畦,當(dāng)為IME(Input Method Editor 輸入法編輯器)輸入字符時(shí)觸發(fā);
  • 變動(dòng)(mutation)事件研儒,當(dāng)?shù)讓覦OM結(jié)構(gòu)發(fā)生變化時(shí)觸發(fā)豫缨。

除了這幾類事件之外,HTML5也定義了一組事件端朵,而有些瀏覽器還會(huì)在DOM和BOM中實(shí)現(xiàn)其他專有事件好芭。這些專有的事件一般都是根據(jù)開發(fā)者需求定制的。

UI事件

UI事件指的是那些不一定與用戶操作有關(guān)的事件冲呢。這些事件在DOM規(guī)范出現(xiàn)之前舍败,都是以這種或那種形式存在的,而在DOM規(guī)范中保留是為了向后兼容。現(xiàn)有的UI事件如下邻薯。

  • DOMActivate:表示元素已經(jīng)被用戶操作(通過鼠標(biāo)或鍵盤)激活裙戏,這個(gè)事件在DOM3級(jí)事件中被廢棄。
  • load:當(dāng)頁(yè)面完全加載后在window上面觸發(fā)弛说,當(dāng)所有框架都加載完畢時(shí)在框架集上面觸發(fā)挽懦,當(dāng)圖像加載完畢時(shí)在<Img>元素上面觸發(fā)翰意,或者當(dāng)嵌入的內(nèi)容加載完畢時(shí)在<object>元素上面觸發(fā)木人。
  • unload:當(dāng)頁(yè)面完全卸載后在window上面觸發(fā),當(dāng)所有框架都卸載后在框架集上面觸發(fā)冀偶,或者當(dāng)嵌入的內(nèi)容卸載完畢后<object>元素上面觸發(fā)醒第。
  • abort:在用戶停止下載過程時(shí),如果嵌入的內(nèi)容沒有加載完进鸠,則在<object>元素上面觸發(fā)稠曼。
  • error:當(dāng)發(fā)生JavaScript錯(cuò)誤時(shí)在window上面觸發(fā),當(dāng)無法加載圖像時(shí)在<img>元素上面觸發(fā)客年,無法加載嵌入內(nèi)容時(shí)<object>上觸發(fā)霞幅,或者當(dāng)一或多個(gè)框架無法加載時(shí)在框架集上觸發(fā)。
  • select:當(dāng)用戶選擇<input>或<textarea>中一或多個(gè)字符時(shí)被觸發(fā)量瓜。
  • resize:當(dāng)窗口或框架的大小變化時(shí)在window或框架上面觸發(fā)司恳。
  • scroll:當(dāng)用戶滾動(dòng)帶滾動(dòng)條的元素中的內(nèi)容時(shí),在該元素上面觸發(fā)绍傲。<body>元素中包含所加載頁(yè)面的滾動(dòng)條扔傅。

多數(shù)這些事件斗魚window對(duì)象或表單控件相關(guān)。

load事件
JavaScript中最常用 的一個(gè)事件就是load烫饼。當(dāng)頁(yè)面完全加載后(包括所有圖像猎塞、JavaScript文件、CSS文件等外部資源)杠纵,就會(huì)觸發(fā)window上面的load事件荠耽。有兩種定義onload事件處理程序的方式。

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

這是通過JavaScript來指定事件處理程序的方式比藻,使用了之前跨瀏覽器的EventUtil對(duì)象骇塘。同樣的,這里也給事件傳入了一個(gè)event對(duì)象韩容。這個(gè)event對(duì)象中不包括有關(guān)這個(gè)事件的任何附加信息款违,但在兼容DOM瀏覽器中,event.target屬性的值會(huì)被設(shè)置為document群凶,而IE并不會(huì)為這個(gè)事件設(shè)置srcElement屬性插爹。

第二種指定onload事件處理程序的方式是為body元素添加一個(gè)onload特性。

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

一般來說,在window上面發(fā)生的任何事件都可以在body元素中通過相應(yīng)的特性來指定赠尾,因?yàn)樵贖TML中無法訪問window元素力穗。實(shí)際上,這只是為了保證向后兼容的一種權(quán)宜之計(jì)气嫁。建議使用JavaScript方式当窗。

圖像上面也可以觸發(fā)load事件。

    <img src="smile.gif" onload="alert('Image loaded.')">

這樣當(dāng)圖像加載完畢后會(huì)顯示一個(gè)警告框寸宵。同樣的崖面,也可以使用JavaScript。

        var img = document.getElementById("myImage");
        EventUtil.addHandler(img,"load",function(event) {
            event = EventUtil.getEvent(event);
            alert(EventUtil.getTarget(event).src);
        })

這里梯影,使用JavaScript指定了onload事件處理程序巫员。同時(shí)也傳入了event對(duì)象,盡管它也不包含什么有用的信息甲棍。不過简识,事件的目標(biāo)是<img>元素,因此可以通過src屬性訪問并顯示該信息感猛。
在創(chuàng)建新的<img>元素時(shí)七扰,可以為其指定一個(gè)事件處理程序,以便圖像加載完畢后給出提示陪白。此時(shí)颈走,最重要的是要在指定src屬性之前指定事件。

        EventUtil.addHandler(window,"load",function() {
            var image = document.createElement("img");
            EventUtil.addHandler(image,"load",function(event) {
                event = EventUtil.getEvent(event);
                alert(EventUtil.getTarget(event).src);
            });
            document.body.appendChild(image);
            image.src = "smile.gif";
        });

首先為window指定了onload事件處理程序拷泽,原因在于疫鹊,向DOM中添加一個(gè)新元素,所以確保頁(yè)面已經(jīng)加載完畢——如果在頁(yè)面加載前操作document.body會(huì)導(dǎo)致錯(cuò)誤司致。然后拆吆,創(chuàng)建一個(gè)新的圖像元素,并設(shè)置了其onload事件處理程序脂矫。最后又將這個(gè)圖像添加到頁(yè)面中枣耀,還設(shè)置了它的src屬性。這里有一點(diǎn)需要注意:新圖像元素不一定要從添加到文檔后才開始下載庭再,只要設(shè)置了src屬性就會(huì)開始下載捞奕。

還有一些元素也以非保準(zhǔn)的方式支持load事件。在IE9+拄轻,F(xiàn)irefox颅围,opera,chrome恨搓,safari3+及更高版本中院促,<script>元素也支持load事件筏养。以便開發(fā)者確定動(dòng)態(tài)加載的JavaScript文件是否加載完畢。只有在設(shè)置了<script>元素的src屬性并將該元素添加到文檔后常拓,才會(huì)開始下載JavaScript文件渐溶,這和img元素不同。換句話說弄抬,對(duì)于<script>元素而言茎辐,指定src屬性和指定事件處理程序的先后順序不重要了。

        EventUtil.addHandler(window,"load",function() {
            var script = document.createElement("script");
            EventUtil.addHandler(script,"load",function(event) {
                alert("Loaded");
            });
            script.src = "example.js";
            document.body.appendChild(script);
        });

unload事件
與load事件對(duì)應(yīng)的是unload事件掂恕,這個(gè)事件在文檔被完全卸載后觸發(fā)拖陆。只要用戶從一個(gè)頁(yè)面切換到另一個(gè)頁(yè)面,就會(huì)發(fā)生unload事件竹海,而利用這個(gè)事件最后情況是清除引用慕蔚,比避免內(nèi)存泄漏丐黄。

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

此時(shí)生成的event對(duì)象在兼容DOM的瀏覽器中只包含target屬性(值為document)斋配。ie8及之前版本則為這個(gè)事件對(duì)象提供了srcElement屬性。
指定事件處理程序的第二種方式灌闺,也是為body元素添加一個(gè)特性艰争。

<body onunload="alert('Unloaded!')">

無論使用哪種方式,都要小心編寫onunload事件處理程序中的代碼桂对。既然unload事件是在一切都被卸載后觸發(fā)甩卓,那么頁(yè)面加載后存在的某些對(duì)象此時(shí)就不一定存在了,此時(shí)蕉斜,操作DOM節(jié)點(diǎn)或者元素的樣式就會(huì)導(dǎo)致錯(cuò)誤逾柿。

resize事件
當(dāng)瀏覽器窗口被調(diào)整到一個(gè)新的高度或?qū)挾葧r(shí),就會(huì)觸發(fā)resize事件宅此。這個(gè)事件在window上面觸發(fā)机错,因此可以通過JavaScript或者body元素中的onresize特性來指定事件處理程序。不過父腕,還是推薦JavaScript方式弱匪。

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

關(guān)于何時(shí)觸發(fā)resize事件,不同瀏覽器有不同機(jī)制璧亮。IE萧诫,Safari,Chrome枝嘶,Opera會(huì)在瀏覽器變化了1像素時(shí)就觸發(fā)resize事件帘饶,然后隨著變量不斷重復(fù)觸發(fā)。Firefox只會(huì)在用戶停止調(diào)整窗口大小時(shí)觸發(fā)resize事件群扶。由于存在差異及刻,注意不要在這個(gè)事件處理程序中加入大計(jì)算量代碼,因?yàn)檫@些代碼有可能被頻繁執(zhí)行,從而導(dǎo)致瀏覽器反應(yīng)明顯變慢提茁。

瀏覽器窗口最小化或最大化也會(huì)觸發(fā)resize事件

scroll事件
雖然scroll事件是在window對(duì)象上發(fā)生的淹禾,但他實(shí)際表示的是頁(yè)面中相應(yīng)元素的變化。在混雜模式下茴扁,可以通過<body>元素的scrollLeft和scrollTop來監(jiān)控這一變化铃岔。

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

以上代碼指定的事件處理程序會(huì)輸出頁(yè)面的垂直滾動(dòng)位置——根據(jù)呈現(xiàn)模式不同使用了不同的元素。

與resize事件類似峭火,scroll事件也會(huì)在文檔被滾動(dòng)期間重復(fù)被觸發(fā)毁习,盡量保持事件處理程序代碼簡(jiǎn)單。


焦點(diǎn)事件

焦點(diǎn)事件會(huì)在頁(yè)面元素獲得或失去焦點(diǎn)時(shí)觸發(fā)卖丸。利用這些事件并與document.hasFocus()方法及document.activeElement屬性配合纺且,可以知曉用戶在頁(yè)面上的行蹤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末稍浆,一起剝皮案震驚了整個(gè)濱河市载碌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衅枫,老刑警劉巖嫁艇,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異弦撩,居然都是意外死亡步咪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門益楼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猾漫,“玉大人,你說我怎么就攤上這事感凤。” “怎么了俊扭?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵队橙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我萨惑,道長(zhǎng)捐康,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任庸蔼,我火速辦了婚禮解总,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘姐仅。我一直安慰自己花枫,他們只是感情好刻盐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著劳翰,像睡著了一般敦锌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上佳簸,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天乙墙,我揣著相機(jī)與錄音,去河邊找鬼生均。 笑死听想,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的马胧。 我是一名探鬼主播汉买,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼佩脊!你這毒婦竟也來了蛙粘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤邻吞,失蹤者是張志新(化名)和其女友劉穎组题,沒想到半個(gè)月后葫男,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抱冷,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年梢褐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旺遮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盈咳,死狀恐怖耿眉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鱼响,我是刑警寧澤鸣剪,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站丈积,受9級(jí)特大地震影響筐骇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜江滨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一铛纬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唬滑,春花似錦告唆、人聲如沸棺弊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)模她。三九已至,卻和暖如春懂牧,著一層夾襖步出監(jiān)牢的瞬間缝驳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工归苍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留用狱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓拼弃,卻偏偏與公主長(zhǎng)得像夏伊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吻氧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容