我要投稿
  • 您當前的位置:中國教育資源網 -> 技術教程 -> 服務器網絡 -> 服務器教程 -> LinuxBSD教程 -> 教程內容
  • [ 收藏本頁教程 ]
  • 生動詳細解釋javascript的冒泡和捕獲

    教程作者:本站    教程來源:本站整理   教程欄目:LinuxBSD教程    收藏本頁

    生動詳細解釋javascript的冒泡和捕獲
    摘要:   原文:Event order 翻譯:hh54188的博客   前言:雖然精通jquery,但對它的原型javascript卻不是很了解,最近在學習javascript中遇到了一些困難,比如冒泡和捕獲,很多次被提到,但又不知究竟應用在何處。找到 ...
      原文:Event order 翻譯:hh54188的博客
      前言:雖然精通jquery,但對它的原型javascript卻不是很了解,最近在學習javascript中遇到了一些困難,比如冒泡和捕獲,很多次被提到,但又不知究竟應用在何處。找到了一些好文章解惑,在這里分享給大家。
      quirksmode的一系列文章都不錯,通俗易懂,這篇只是一系列中的某一篇,有機會把javascript這系列都翻譯給大家。
     ,句子中有標注“(?)”表示我對這個句子不是很理解,可能有誤。正式開始:
      事件的發生順序
      這個問題的起源非常簡單,假設你在一個元素中又嵌套了另一個元素
    -----------------------------------
    | element1                        |
    |   -------------------------     |
    |   |element2               |     |
    |   -------------------------     |
    |                                 |
    -----------------------------------
    :并且兩者都有一個onClick事件處理函數(event handler)。如果用戶單擊元素2,則元素1和元素2的單擊事件都會被觸發。但是哪一個事件先被觸發?哪一個事件處理函數會被首先執行?換句話說,事件的發生順序到底如何?
      兩種模型
      不出所料,在那些“不堪回首”(瀏覽器大戰)的日子里,Netscape和微軟有兩種截然不同的處理方法:
    Netscape主張元素1的事件首先發生,這種事件發生順序被稱為捕獲型
    微軟則保持元素2具有優先權,這種事件順序被稱為冒泡型
      這兩種事件順序是截然相反的。Explorer瀏覽器只支持冒泡事件,Mozilla,Opera7和Konqueror兩者都支持。而更古老的opera和iCab兩者都不支持
      捕獲型事件
      當你使用捕獲型事件時
                   | |
    ---------------| |-----------------
    | element1     | |                |
    |   -----------| |-----------     |
    |   |element2  \ /          |     |
    |   -------------------------     |
    |        Event CAPTURING          |
    -----------------------------------
    :元素1的事件處理函數首先被觸發,元素2的事件處理函數最后被觸發
      冒泡型事件
      當你使用冒泡型事件時
                   / \
    ---------------| |-----------------
    | element1     | |                |
    |   -----------| |-----------     |
    |   |element2  | |          |     |
    |   -------------------------     |
    |        Event BUBBLING           |
    -----------------------------------
    :元素2 的處理函數首先被觸發,元素1其次
      W3C 模型
      W3c明智的在這場爭斗中選擇了一個擇中的方案。任何發生在w3c事件模型中的事件,首是進入捕獲階段,直到達到目標元素,再進入冒泡階段
                     | |  / \
    -----------------| |--| |-----------------

    | element1       | |  | |                |
    |   -------------| |--| |-----------     |
    |   |element2    \ /  | |          |     |
    |   --------------------------------     |
    |        W3C event model                 |
    ------------------------------------------
      為一個web開發者,你可以選擇是在捕獲階段還是冒泡階段綁定事件處理函數,這是通過addEventListener()方法實現的,如果這個函數的最后一個參數是true,則在捕獲階段綁定函數,反之false,在冒泡階段綁定函數。
      假設你要做
    1
    2
    3
    element1.addEventListener('click',doSomething2,true)
     
    element2.addEventListener('click',doSomething,false)
      如果用戶單擊元素2,則接下來會發生:
    (事件在這里就像一個觀光客,由外至內游覽,逐漸接近被觸發的主要元素,然后又反向離開)
    單擊事件首先進入捕獲階段開始(逐漸接近元素2的方向)。查看元素2的祖先元素中是否有在捕獲階段有onclick處理函數的
    發現元素1有一個,于是doSomething2被執行
    事件檢查到目標自己(元素2),捕獲階段沒有發現更多的處理函數了。事件開始進入冒泡階段,想當然執行doSomething(),這個綁定于元素2冒泡階段的函數。
    事件向遠離元素2的方向,查看是否有任何祖先元素在冒泡階段綁定了一個處理函數。沒有這樣的情況,所以什么也沒有發生
      相反的情況是:
    1
    2
    3
    element1.addEventListener('click',doSomething2,false)
     
    element2.addEventListener('click',doSomething,false)
      現在如果用戶點擊元素2會發生:
    單擊事件進入捕獲階段。查看元素2的祖先元素中是否有在捕獲階段有onclick處理函數的,結果一無所獲
    事件檢查到目標自己。事件開始進入冒泡階段,并且執行綁定于元素2冒泡階段的函數。doSomething()
    事件開始遠離目標,檢查元素2的祖先元素中是否有在冒泡階段綁定了處理函數的
    發現了一個,于是元素1的doSomething2()被執行
     
      兼容性和傳統模式
    在支持w3c dom(文檔對象模型) 的瀏覽器中,傳統的事件綁定方法是
    1
    element1.onclick = doSomething2;
    默認被視為在綁定于冒泡階段
      使用冒泡型事件
      很少的開發人員會有意識的去使用冒泡型事件或者捕獲型事件。在他們今天制作的網頁中,沒有必要讓一個事件因為冒泡而被好幾個函數處理。但是有時用戶 通常會很疑惑,因為在他們只點擊了一次鼠標之后出現了許多種情況(多個函數被執行,因為冒泡)。而大多數情況下你還是希望你的處理函數相互獨立的。當用戶 點擊了某一個元素,發生什么,點擊另一個元素,又對應發生些什么,相互獨立,而不因為冒泡連鎖。一直在發生
      首先你要明白的是事件捕獲或者冒泡一直在發生。如果你給整個頁面文檔的定義一個通用onclick處理函數
    1
    2
    3
    4
    5
    document.onclick = doSomething;
     
    if (document.captureEvents) document.captureEvents(Event.CLICK);
     
    //第二句話我也不知道什么意思,初學者,希望有能人能解釋
      在頁面上單擊任何元素的單擊事件,最終會冒泡至頁面最高文檔層,因此觸發那個通用的處理函數,除非之前一個處理函數明確的指出終止冒泡,這樣才冒泡才不會傳播到整個文檔層面
      用法(這一小節翻譯的不好,因為沒有實戰,我也不是很理解,可以在留言中補充,我會更新)
      因為任何事件傳播終止于頁面文檔(這個最高層),這使默認的事件處理函數變得可能,假設你有這樣一個頁面
    ------------------------------------
    | document                         |
    |   ---------------  ------------  |
    |   | element1    |  | element2 |  |
    |   ---------------  ------------  |
    |                                  |
    ------------------------------------
    1
    2
    3
    element1.onclick = doSomething;
    element2.onclick = doSomething;
    document.onclick = defaultFunction;
      現在如果用戶單擊元素1或者元素2,doSomething()將被執行。如果你愿意的話,如果你不想讓事件冒泡至執行 defaultFunction(),你可以在這里阻止事件冒泡向上傳播,。但是如果用戶點擊頁面上的其他部位,defaultFunction()還是 會被執行。這樣的效果或許有時能用的上。
      設置頁面­——使處理函數有范圍較大的觸發面積,在“拖拽效果”腳本中是必須的。一般來說在某一個元素層上發生 mousedown事件意味著選擇了這個元素,并且使它能夠響應mousemove事件。雖然mousedown通常綁定于這個元素層上以避免瀏覽器 bug,但是其他兩者的事件函數的范圍必須是整個頁面(?)
      記住瀏覽器學的第一法則(First Law of Browserology)是:一切皆有可能(anything can happen),并且是在你起碼有點準備的時候。所以有可能發生的是,用戶拖拽時,大幅度在頁面上移動他的鼠標,腳本卻不能在大幅度中做出反應,以至于鼠 標也就不再停留在元素層上了
    如果onmouseover處理函數綁定在元素層上,這個元素層不會再對鼠標的移動有任何反應,這會讓用戶覺得奇怪
    如果onmouseup處理函數綁定在元素層上,事件也不能被觸發,后果是,用戶想放下這個元素層后,元素層持續對鼠標移動做出反應。這會引起(用戶)更多的迷惑(?)
      所以在這個例子中,事件冒泡非常的有用,因為將你的處理函數放在頁面層能保證他們一直能被執行
      把它給關了
      但是一般情況下,你會想關了所有的冒泡和捕獲以保證函數之間不會打擾到對方。除此之外,如果你的文檔結構相當的復雜(許多table之間相互嵌套或 者諸如此類),你也會為了節省系統資源,而關閉冒泡。此時瀏覽器不得不檢查目標元素的每一  個祖先,看是否它有一個處理函數。即使一個都沒有找到,剛剛的搜 索同樣花費不少時間
      在微軟的模型中,你必須設置事件的cancelBubble的屬性為true
    1
    window.event.cancelBubble = true
      在w3c模型中你必須調用事件的stopPropagation()方法
    1
    e.stopPropagation()
      這會阻止所有冒泡向外傳播。而作為跨瀏覽器解決方案應該這么作:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function doSomething(e)
     
    {
         if (!e) var e = window.event;
     
    e.cancelBubble = true;
     
    if (e.stopPropagation) e.stopPropagation();
     
    }
      在支持cancelBubble屬性的瀏覽器中設置cancelBubble無傷大雅。瀏覽器會聳一聳肩然后創造一個這個屬性。當然這也并不能真正的取消冒泡,但至少能保證這條命令是安全正確的
    currentTarget
      像我們之前看到的一樣,一個事件用target或者是srcElement屬性用來表示事件究竟發生在哪個目標元素上(即用戶最初點擊的元素)。在我們的例子中是元素2,因為我們單擊了它。
      非常重要的是,要明白在捕獲或者冒泡階段的目標元素是不變的,它始終與元素2相關聯。
      但是假設我們綁定了以下函數
    1
    2
    3
    element1.onclick = doSomething;
     
    element2.onclick = doSomething;
      如果用戶單擊元素2, doSomething()會被執行兩次。但是你怎么知道哪個html元素正在響應這個事件?target/srcElement也沒有給出線索,但人們總是更傾向于元素2,因為它是引起事件的原因(因為用戶點擊的是它)。
      為了解決這個問題,w3c 增加了currentTarget這個屬性,它就指向正在處理事件的元素:這恰是我們需要的。很不幸的是微軟模型中并沒有相似的屬性
      你也可以使用”this”關鍵字。在上面的例子中,它相當于正在處理事件的html元素,就像currentTarget。
      微軟模型的問題
      但是當你使用微軟事件綁定模型時,this關鍵字并不相當于HTML元素。聯想缺少類似currentTarget屬性的微軟模型(?)——按上面的代碼操作的話,你這么做便意味著:
    1
    2
    3
    element1.attachEvent('onclick',doSomething)
     
    element2.attachEvent('onclick',doSomething)
      你無法確切知道哪一個HTML元素正在負責處理事件,這是微軟事件綁定模型最嚴重的問題,對我來說,這也是我從不使用它的原因,哪怕是在開發僅供Windows下的IE的應用程序
      我希望能夠盡快增加currentTarget類似的屬性——或者遵循標準?web開發者們需要這些信息
      后記:
      因為沒有實戰過javascript,所以這篇文章有些地方我并不是很理解,只能硬生的翻譯出來,比如談拖拽效果的那一段,如果大家有什么補充和疑問可以留言給我,謝謝支持啦!

    我要投稿   -   廣告合作   -   關于本站   -   友情連接   -   網站地圖   -   聯系我們   -   版權聲明   -   設為首頁   -   加入收藏   -   網站留言
    Copyright © 2009 - 20012 www.obscurenation.com All Rights Reserved.中國教育資源網 版權所有  
     
    彩16app 海丰县 | 灵璧县 | 佛山市 | 大姚县 | 青海省 | 藁城市 | 滦南县 | 个旧市 | 梓潼县 | 肥城市 | 西城区 | 德昌县 | 微山县 | 渭源县 | 盐城市 | 乳山市 | 璧山县 | 正宁县 | 焦作市 | 肇庆市 | 砚山县 | 芦山县 | 封开县 | 宝丰县 | 宝坻区 | 东乡族自治县 | 南宁市 | 孝感市 | 彭阳县 | 武平县 | 石河子市 | 永昌县 | 会同县 | 贵港市 | 长寿区 | 阿坝县 | 泾川县 | 民勤县 | 灵山县 | 竹溪县 | 临海市 | 涡阳县 | 额济纳旗 | 盐津县 | 蒙山县 | 桦甸市 | 天峨县 | 连山 | 玛纳斯县 | 凤山市 | 霞浦县 | 洛阳市 | 寿光市 | 自贡市 | 惠水县 | 合阳县 | 广汉市 | 龙海市 | 泽库县 | 兴安县 | 乾安县 | 佛坪县 | 北安市 | 富源县 | 滦平县 | 南昌市 | 大竹县 | 科技 | 武胜县 | 宽甸 | 莱西市 | 郴州市 | 忻城县 | 望城县 | 长垣县 | 乌拉特中旗 | 湖州市 | 遵化市 | 蓝山县 | 五峰 | 河北区 | 枣庄市 | 中宁县 | 满城县 | 原阳县 | 甘德县 | 班玛县 | 绥江县 | 巫山县 | 汶川县 | 濮阳县 | 磴口县 | 博乐市 | 南部县 | 山西省 | 百色市 | 通州市 | 同仁县 | 蛟河市 | 嘉祥县 | 田东县 | 屏东县 | 塘沽区 | 星座 | 南部县 | 西和县 | 文昌市 | 松溪县 | 丹东市 | 永春县 | 瓦房店市 | 娄底市 | 西丰县 | 宜良县 | 石景山区 | 石台县 | 牟定县 | 四子王旗 | 吉林市 | 来凤县 | 翁源县 | 红原县 | 平顶山市 | 建始县 | 宁乡县 | 望江县 | 卫辉市 | 桦川县 | 台湾省 | 商水县 | 鄂尔多斯市 | 图片 | 芮城县 | 平凉市 | 德州市 | 攀枝花市 | 临西县 | 太和县 | 福鼎市 | 嘉鱼县 | 若尔盖县 | 万州区 | 会东县 | 新田县 | 乐安县 | 河北区 | 钟祥市 | 西丰县 | 中江县 | 彭阳县 | 桦川县 | 光山县 | 威信县 | 克拉玛依市 | 平和县 | 建宁县 | 庆元县 | 静安区 | 金华市 | 佛学 | 涟源市 | 竹山县 | 承德市 | 曲水县 | 清新县 | 招远市 | 台中市 | 巩义市 | 皋兰县 | 营山县 | 化隆 | 常州市 | 泸西县 | 游戏 | 岳普湖县 | 新源县 | 天祝 | 灵璧县 | 池州市 | 通化县 | 秀山 | 城口县 | 会理县 | 邳州市 | 乌什县 | 三门峡市 | 天气 | 方山县 | 道孚县 | 永年县 | 兰考县 | 临邑县 | 虞城县 | 宜都市 | 岳池县 | 昭平县 | 吴江市 | 正镶白旗 | 襄汾县 | 凉城县 | 合作市 | 安乡县 | 棋牌 | 海城市 | 萨嘎县 | 彰武县 | 苍梧县 | 绵竹市 | 正宁县 | 建水县 | 尖扎县 | 丁青县 | 鹤庆县 | 陆良县 | 屯昌县 | 浦北县 | 芜湖县 | 沁源县 | 甘泉县 | 梁山县 | 新平 | 建阳市 | 陆良县 | 望都县 | 枞阳县 | 安陆市 | 封开县 | 中西区 | 保亭 | 错那县 | 治多县 | 平武县 | 西林县 | 通山县 | 梅河口市 | 舟山市 | 民丰县 | 南澳县 | 正定县 | 长沙市 | 泾阳县 | 阜宁县 | 舞阳县 | 萨迦县 | 镇沅 | 无极县 | 抚远县 | 鄂伦春自治旗 | 揭西县 | 宁国市 | 涿鹿县 |