【讀書筆記】:《編寫可維護(hù)的JavaScript》第07章 事件處理

第07章 事件處理

7.1 典型用法

當(dāng)事件觸發(fā)時(shí)留储,事件對(duì)象(event對(duì)象)會(huì)作為回調(diào)參數(shù)傳入事件處理程序中。event對(duì)象包含所有和事件相關(guān)的信息丐膝,包括事件的宿主(target)以及其他和事件類型相關(guān)的數(shù)據(jù)。鼠標(biāo)事件會(huì)將其位置信息暴露在event對(duì)象上浑此,鍵盤事件會(huì)將案件信息暴露在event對(duì)象上凛俱,觸屏事件會(huì)將觸摸位置和持續(xù)時(shí)間暴露在event 對(duì)象上。只有提供了所有這些信息原叮,UI才會(huì)正確地執(zhí)行交互篇裁。

在很多場(chǎng)景中团甲,你只是用到了event所提供信息的一小部分身腻,看下面這段代碼脐区。

// 不好的寫法
function handleClick(event) {
    "use strick";
    var popup = document.getElementById("popup");
    popup.style.left = event.clientX + "px";
    popup.style.top = event.clientY + "px";
    popup.className = "reveal";
}

盡管這段代碼看起來非常簡(jiǎn)單并且沒什么問題,但實(shí)際上是不好的寫法媒佣,因?yàn)檫@種做法有局限性默伍。

7.2 規(guī)則1:隔離應(yīng)用邏輯

上段實(shí)例代碼的第一個(gè)問題是事件處理程序包含了應(yīng)用邏輯(application logic)。應(yīng)用邏輯是和應(yīng)用相關(guān)的功能性代碼狸剃,而不是和用戶行為相關(guān)的捕捂。上段代碼中,應(yīng)用邏輯是在特定位置顯示一個(gè)彈出框允悦。盡管這個(gè)交互應(yīng)當(dāng)是在用戶點(diǎn)擊某個(gè)特定元素時(shí)發(fā)生,但情況并不總是如此全闷。

將應(yīng)用邏輯從所有事件處理程序中抽離出來的做法是一種最佳實(shí)踐屏鳍,因?yàn)檎f不定什么時(shí)候其他地方就會(huì)觸發(fā)同一段邏輯。比如山涡,有時(shí)你需要用戶鼠標(biāo)移到某個(gè)元素上時(shí)判斷是否顯示彈出框,或者按下鍵盤的某個(gè)鍵時(shí)也作同樣的邏輯判斷系吩。這樣多個(gè)時(shí)間的處理程序執(zhí)行了同樣的邏輯穿挨,而你的代碼卻不小心復(fù)制了多份。

如果對(duì)上段實(shí)例代碼進(jìn)行重構(gòu)贞绵,第一步是將處理彈出框邏輯代碼放入一個(gè)單獨(dú)的函數(shù)中,這個(gè)函數(shù)很可能掛載于為該應(yīng)用定義的一個(gè)全局對(duì)象上母蛛。事件處理程序應(yīng)當(dāng)總是在一個(gè)相同的全局對(duì)象中,因此就有了以下兩個(gè)方法:

var MyApplication = {
    handleClick: function (event) {
        "use strict";
        this.showPopup(event);
    },

    showPopup: function (event) {
        "use strict";
        var popup = document.getElementById("popup");
        popup.style.left = event.clientX + "px";
    }
};

addListener(element, "click", function (event) {
    "use strict";
    MyApplication.handleClick(event);
});

之前的事件處理程序中包含的所有應(yīng)用邏輯現(xiàn)在轉(zhuǎn)移到了MyApplication.showPopup()方法中。現(xiàn)在MyApplication.handleClick()方法只做一件事情违帆,即調(diào)用MyApplication.showPopup()狈醉。

7.3 規(guī)則2:不要分發(fā)事件對(duì)象

在剝離出應(yīng)用邏輯之后,上段代碼還存在一個(gè)問題班巩,即event對(duì)象被無節(jié)制地分發(fā)。它從匿名的事件處理函數(shù)傳入了MyApplication.handleClick()抑进,然后又傳入了MyApplication.showPopup()。正如上文提到的信殊,event對(duì)象上包含很對(duì)和事件相關(guān)的額外信息,而這段代碼只用到了其中的兩個(gè)而已良拼。

應(yīng)用邏輯不應(yīng)當(dāng)依賴event對(duì)象來正確完成功能仲吏,原因如下:
如果你想測(cè)試這個(gè)方法,你必須重新創(chuàng)建一個(gè)event對(duì)象并將它作為參數(shù)傳入许帐。
最佳的辦法是讓事件事件處理程序使用event對(duì)象來處理事件距芬,然后拿到所有需要的數(shù)據(jù)傳給應(yīng)用邏輯。例如 MyApplication.showPopup() 方法只需要使用兩個(gè)數(shù)據(jù)离斩,x坐標(biāo)和y坐標(biāo):

// 好的寫法
var MyApplication= {
    handleClick: function (event) {
        "use strict";
        this.showPopup(event.clientX, event.clientY);
    },

    showPopup: function (x, y) {
        "use strict";
        var pupup = document.getElementById("popup");
        pupup.style.left = x;
        pupup.style.top = y;
        pupup.className = "reveal";
    }
};

addListener(element, "click", function (event) {
    "use strict";
    MyApplication.handleClick(event);
});

這段重寫的代碼中,MyApplication.handleClick() 將 x 坐標(biāo)和 y 坐標(biāo)傳入了MyApplication.showPopup()。代替了之前傳入的事件對(duì)象漾岳』妊颍可以很清晰地看到MyApplication.showPopup()所期望傳入的參數(shù),并且測(cè)試或代碼的任意位置都可以很輕松地直接調(diào)用這段邏輯:

MyApplication. showPopup(10,20);

當(dāng)處理事件時(shí),最好讓事件處理城西稱謂接觸到event對(duì)象的唯一函數(shù)狞悲。事件處理程序應(yīng)當(dāng)在進(jìn)入應(yīng)用邏輯之前針對(duì)event對(duì)象執(zhí)行任何必要的操作,包括阻止默認(rèn)事件或事件冒泡荸恕,都應(yīng)當(dāng)直接包含在事件處理程序中。

var MyApplication = {
    handleClick: function (event) {
        "use strict";
        // 假設(shè)事件支持 DOM Level2
        event.preventDefault();
        event.stopPropagation();
        this.showPopup(event.clientX, event.clientY);
    },

    showPopup: function (x, y) {
        "use strict";
        var pupup = document.getElementById("popup");
        pupup.style.left = x;
        pupup.style.top = y;
        pupup.className = "reveal";
    }
};

addListener(element, "click", function (event) {
    "use strict";
    MyApplication.handleClick(event);
});
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末县昂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狸驳,更是在濱河造成了極大的恐慌撰糠,老刑警劉巖旨袒,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辉词,死亡現(xiàn)場(chǎng)離奇詭異敷搪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)闸与,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門冰评,熙熙樓的掌柜王于貴愁眉苦臉地迎上來解孙,“玉大人弛姜,你說我怎么就攤上這事苍在。” “怎么了初肉?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)妄壶。 經(jīng)常有香客問我,道長(zhǎng)狡逢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮徊哑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梢莽。我一直安慰自己涮雷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拾枣,像睡著了一般司蔬。 火紅的嫁衣襯著肌膚如雪肺缕。 梳的紋絲不亂的頭發(fā)上同木,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天芥映,我揣著相機(jī)與錄音坞嘀,去河邊找鬼。 笑死矢渊,一個(gè)胖子當(dāng)著我的面吹牛昆淡,可吹牛的內(nèi)容都是我干的避凝。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼含潘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起漱逸,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诀黍,失蹤者是張志新(化名)和其女友劉穎咒彤,沒想到半個(gè)月后镶柱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拄氯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖胯府,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤急迂,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布阴幌,位于F島的核電站渊抽,受9級(jí)特大地震影響懒闷,放射性物質(zhì)發(fā)生泄漏帮辟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望润樱。 院中可真熱鬧,春花似錦店展、人聲如沸赂蕴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奋构。三九已至,卻和暖如春醋火,著一層夾襖步出監(jiān)牢的瞬間芥驳,已是汗流浹背假抄。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工脚祟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留为黎,地道東北人铭乾。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓捌斧,卻偏偏與公主長(zhǎng)得像捞蚂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子队贱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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