国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

瀏覽器事件解析

Mike617 / 617人閱讀

摘要:瀏覽器事件之間的關(guān)系程序采用了異步事件驅(qū)動(dòng)編程模型,維基百科對(duì)它的解釋是事件驅(qū)動(dòng)程序設(shè)計(jì)是一種電腦程序設(shè)計(jì)模型。事件驅(qū)動(dòng)程序模型基本的實(shí)現(xiàn)原理基本上都是使用事件循環(huán),這部分內(nèi)容涉及瀏覽器事件模型回調(diào)原理。

JavaScript、瀏覽器、事件之間的關(guān)系

JavaScript程序采用了異步事件驅(qū)動(dòng)編程(Event-driven programming)模型,維基百科對(duì)它的解釋是:

事件驅(qū)動(dòng)程序設(shè)計(jì)(Event-driven programming)是一種電腦程序設(shè)計(jì)模型。這種模型的程序運(yùn)行流程是由用戶的動(dòng)作(如鼠標(biāo)的按鍵,鍵盤的按鍵動(dòng)作)或者是由其他程序的消息來決定的。相對(duì)于批處理程序設(shè)計(jì)(batch programming)而言,程序運(yùn)行的流程是由程序員來決定。批量的程序設(shè)計(jì)在初級(jí)程序設(shè)計(jì)教學(xué)課程上是一種方式。然而,事件驅(qū)動(dòng)程序設(shè)計(jì)這種設(shè)計(jì)模型是在交互程序(Interactive program)的情況下孕育而生的

簡(jiǎn)言之,在web前端編程里面JavaScript通過瀏覽器提供的事件模型API和用戶交互,接收用戶的輸入。

由于用戶的行為是不確定的。這種場(chǎng)景是傳統(tǒng)的同步編程模型沒法解決的,因?yàn)槟悴豢赡艿扔脩舨僮魍炅瞬艌?zhí)行后面的代碼。所以在javascript中使用了異步事件,也就是說:js中的事件都是異步執(zhí)行的

事件驅(qū)動(dòng)程序模型基本的實(shí)現(xiàn)原理基本上都是使用 事件循環(huán)(Event Loop),這部分內(nèi)容涉及瀏覽器事件模型、回調(diào)原理。

JavaScript DOM、BOM模型中,同樣異步的還有setTimeout,XMLHTTPRequest這類API并不是JavaScript語言本身就有的。

事件綁定的方法

事件綁定有3種方法:

行內(nèi)綁定

直接在DOM元素上通過設(shè)置on + eventType綁定事件處理程序。例如:

點(diǎn)擊我

這種方法有兩個(gè)缺點(diǎn):

事件處理程序和HTML結(jié)構(gòu)混雜在一起,不符合MVX的規(guī)范。為了讓內(nèi)容、表現(xiàn)和行為分開,我們應(yīng)該避免這種寫法。

這樣寫的代碼判斷具有全局作用域,可能會(huì)產(chǎn)生命名沖突,導(dǎo)致不可預(yù)見的嚴(yán)重的后果。

在DOM元素上直接重寫事件回調(diào)函數(shù)

使用DOM Element上面的on + eventType屬性 API

var el = getElementById("button");  //button是一個(gè)

這種方法也有一個(gè)缺點(diǎn):后綁定的函數(shù)會(huì)覆蓋之前的函數(shù)。比如我們注冊(cè)一個(gè)window.onload事件,可能會(huì)覆蓋某個(gè)庫中已有的事件函數(shù)。當(dāng)然,這個(gè)可以有解決方法:

function addEvent(element, EventName, fun) {   //EventName = "on" + eventType
    var oldFun = element[EventName];
    if (typeof oldFun !== "function") {
        element[EventName] = fun;
    } else {
        element[EventName] = function() {
            oldFun();
            fun();
        };
    }
}

addEvent(window, "onload", function() { alert("onload 1") });
addEvent(window, "onload", function() { alert("onload 2") });

當(dāng)然,一般情況下使用DOM Ready就可以了,因?yàn)镴avaScript在DOM加載完就可以執(zhí)行了

標(biāo)準(zhǔn)綁定方法

標(biāo)準(zhǔn)的綁定方法有兩種,addEventListener和attachEvent前者是標(biāo)準(zhǔn)瀏覽器支持的API,后者是IE8以下瀏覽器支持的API:

//例如給一個(gè)button注冊(cè)click事件
var el = getElementById("button");  //button是一個(gè)

需要注意的是:

addEventLister的第一個(gè)參數(shù)事件類型是不加on前綴的,而attachEvent中需要加on前綴。

addEventLister中的事件回調(diào)函數(shù)中的this指向事件元素target本身,而attachEvent中的事件回調(diào)函數(shù)的this指向的是window。

addEventLister有第三個(gè)參數(shù),true表示事件工作在捕獲階段,false為冒泡階段(默認(rèn)值:false)。而attachEvent只能工作在冒泡階段。

在chrome中運(yùn)行如下代碼:

click me

點(diǎn)擊后彈出順序是: 3 -> 4 -> 5 -> 1

這里第4行代碼覆蓋了行內(nèi)的onclick定義,如果注釋了這一行,輸入順序?yàn)椋?2 -> 4 -> 5 -> 1,而addEventListener之間不會(huì)發(fā)生覆蓋。

解除事件綁定

對(duì)于上述的前二個(gè)方法,解除事件綁定只需要將對(duì)應(yīng)的事件函數(shù)設(shè)為null,就可以了:

var el = document.getElementById("button");
el.onclick = null;

對(duì)于上述第三種方法使用removeListen()方法即可,在IE8中,對(duì)應(yīng)使用detachEvent()。注意,他們和上面的注冊(cè)方法一一對(duì)應(yīng),不能混用。

//這是一段錯(cuò)誤代碼,不能實(shí)現(xiàn)事件移除

//建立一個(gè)事件
var el = document.getElementById("button");  //button是一個(gè)

以上的錯(cuò)誤在于事件函數(shù)這樣定義時(shí),雖然看著完全一樣,但在內(nèi)存中地址不一樣。這樣一來,電腦不會(huì)認(rèn)為解除的和綁定的是同一個(gè)函數(shù),自然也就不會(huì)正確解除。應(yīng)該這樣寫:

//建立一個(gè)事件
var el = document.getElementById("button");  //button是一個(gè)
事件的捕獲與冒泡

之前說addEventListener函數(shù)的第三個(gè)參數(shù)表示捕獲和冒泡,這個(gè)是一個(gè)重點(diǎn)!

我自己描述一下他們的定義就是:

冒泡:在一個(gè)元素上觸發(fā)的某一事件,會(huì)在這個(gè)元素的父輩元素上會(huì)依次由內(nèi)向外觸發(fā)該事件,直到window元素。

捕獲:在一個(gè)元素上觸發(fā)的某一事件,這個(gè)元素的每一層的所有子元素上觸發(fā)該事件,并逐層向內(nèi),直到所有元素不再有子元素。

如下圖(注:圖片來自百度搜索)

事件間回到函數(shù)參數(shù)是一個(gè)事件對(duì)象,它里面包括許多事件屬性和方法,比如,我們可以用以下方式阻止冒泡和默認(rèn)事件:

//該例子只寫了handler函數(shù)
function handler(event) {
    event = event || window.event;
    //阻止冒泡
    if (event.stopPropagation) {
        event.stopPropagation();      //標(biāo)準(zhǔn)方法
    } else {
        event.cancelBubble = true;    // IE8
    }
    //組織默認(rèn)事件
    if (event.perventDefault) {
        event.perventDefault();      //標(biāo)準(zhǔn)方法
    } else {
        event.returnValue = false;    // IE8
    }
}

其次,普通注冊(cè)事件只能阻止默認(rèn)事件,不能阻止冒泡

element = document.getElemenById("submit");
element.onclick = function(e){
    /*...*/
    return false;    //通過返回false,阻止冒泡
}
事件對(duì)象

事件函數(shù)中有一個(gè)參數(shù)是事件對(duì)象,它包含了事件發(fā)生的所有信息,比如鍵盤時(shí)間會(huì)包括點(diǎn)擊了什么按鍵,包括什么組合鍵等等,而鼠標(biāo)事件會(huì)包括一系列屏幕中的各種坐標(biāo)和點(diǎn)擊類型,甚至拖拽等等。當(dāng)然,它里面也會(huì)包括很多DOM信息,比如點(diǎn)擊了什么元素,拖拽進(jìn)入了什么元素,事件的當(dāng)前狀態(tài)等等。

這里關(guān)于事件兼容性有必要強(qiáng)調(diào)一下:

document.addEventListener("click", function(event) {
    event = event || window.event;   //該對(duì)象是注冊(cè)在window上的
    console.log(event);   //可以輸出事件對(duì)象看一看, 屬性很多很多
    var target = event.target || event.srcElement;  //前者是標(biāo)準(zhǔn)事件目標(biāo),后者是IE的事件目標(biāo)
},false);

關(guān)于鼠標(biāo)事件坐標(biāo)的問題,可以看另一篇博客:元素和鼠標(biāo)事件的距離屬性

事件觸發(fā)

除了用戶操作以外,我們也可以寫代碼主動(dòng)觸發(fā)一個(gè)事件,以ele元素的click事件為例:

ele.click();   //觸發(fā)ele元素上的單擊事件
事件代理

有時(shí)候我們需要給不存在的的一段DOM元素綁定事件,比如用戶動(dòng)態(tài)添加的元素,或者一段 Ajax 請(qǐng)求完成后渲染的DOM節(jié)點(diǎn)。一般綁定事件的邏輯會(huì)在渲染前執(zhí)行,但綁定的時(shí)候找不到元素所以并不能成功。

為了解決這個(gè)問題,我們通常使用事件代理/委托(Event Delegation)。而且通常來說使用 事件代理的性能會(huì)比多帶帶綁定事件高很多,我們來看個(gè)例子。

傳統(tǒng)注冊(cè)事件方法,當(dāng)內(nèi)容很多時(shí)效率低,不支持動(dòng)態(tài)添加元素

  • item-1
  • item-2
  • item-3
  • item-4
  • item-5

事件委托注冊(cè)方法,不論內(nèi)容有多少都只注冊(cè)1次,支持動(dòng)態(tài)添加元素:

  • item-1
  • item-2
  • item-3
  • item-4
  • item-5
事件封裝

很明顯,處理瀏覽器兼容太麻煩了,所以這里把js中的事件注冊(cè)相關(guān)函數(shù)封裝一下,作為整理。

//均采用冒泡事件模型
var myEventUtil={
    //添加事件函數(shù)
    addEvent: function(ele, event, func){
        var target = event.target || event.srcElement;
        if(ele.addEventListener){
            ele.addEventListener(event, func, false);
        } else if(ele.attachEvent) {
            ele.attachEvent("on" + event, func);   //func中this是window
        } else {
            ele["on" + event] = func;    //會(huì)發(fā)生覆蓋
        }
    },
    //刪除事件函數(shù)
    delEvent:function(ele, event, func) {
        if(ele.removeEventListener){
            ele.removeEventListener(event, func, false);
        } else if(ele.detachEvent) {
            ele.detachEvent("on" + event, func);
        } else {
            ele["on" + event] = null;
        }
    },
    //獲取觸發(fā)事件的源DOM元素
    getSrcElement: function(event){
        return event.target || event.srcElement;
    },
    //獲取事件類型
    getType: function(event){
        return event.type;
    },
    //獲取事件
    getEvent:function(event){
        return event || window.event;
    },
    //阻止事件冒泡
    stopPropagation: function(event) {
        if(event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBuble = false;
        }
    },
    //禁用默認(rèn)行為
    preventDefault: function(event){
        if(event.preventDefault){
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    }
};
jQuery中的事件

需要注意的是: JQuery中的事件都工作在冒泡階段,且只能工作在冒泡階段

注冊(cè)、解除事件

方法一:

//不會(huì)發(fā)生覆蓋,但不利于解除,不能動(dòng)態(tài)操作事件

$("#button").click(function(){   //注冊(cè)一個(gè)click事件,當(dāng)然可以用其他事件名的函數(shù)注冊(cè)其他事件
  console.log("clicked");
});

方法二:

//不會(huì)發(fā)生覆蓋,利于解除,不能動(dòng)態(tài)操作事件

//注冊(cè)一個(gè)事件
$("#button").bind("click", function() {    //注冊(cè)一個(gè)click事件,當(dāng)然可以用其他事件名的函數(shù)注冊(cè)其他事件
  console.log("clicked");
});
//當(dāng)然還可以這樣寫,給事件指定命名空間
$(document).bind("click.handler1", function() { console.log(1);})
$(document).bind("click.handler2", function() { console.log(2);})

//解除一個(gè)事件
$("#button").unbind(".handler1");    //解除元素上所以handler1命名空間中的事件
$("#button").unbind("click.handler2");   // 解除元素上的click.handler2事件
$("#button").unbind("click");            // 解除元素上所有點(diǎn)擊事件
$("#button").unbind()                    // 解除元素上所有事件

//bind()方法還介受3個(gè)參數(shù)形式,這里就不贅述了,感興趣可以自己看看相關(guān)資料。

方法三:

//不會(huì)發(fā)生覆蓋,但不利于解除,能動(dòng)態(tài)操作事件,依賴于事件冒泡

//注冊(cè)事件
$(document).delegate(".item", "click", function(){console.log(this.innerHTML);});   //第一個(gè)是選擇器, 第二個(gè)是事件類型, 第三個(gè)是事件函數(shù)

//移除事件
$(document).undelegate(".item", "click", handler);  //移除元素上指定事件
$(document).undelegate(".item", "click");  //移除元素上所有click事件
$(document).undelegate(".item");  //移除元素上所有事件

方法四:

//不會(huì)發(fā)生覆蓋,但不利于解除,能動(dòng)態(tài)操作事件,不依賴于事件冒泡

//注冊(cè)事件
#(".item").live("click", function(){console.log(this.innerHTML);})  //第一參數(shù)是事件類型, 第二參數(shù)是事件函數(shù)

//移除事件
$(".item").die("click", handler);  //移除元素上指定click事件
$(".item").die("click");  //移除元素上所有click事件

兩個(gè)簡(jiǎn)化方法:

//hover方法
$("#button").hover(function(){
        //鼠標(biāo)移入時(shí)的動(dòng)作,不冒泡
    }, function(){
        //鼠標(biāo)移出時(shí)的動(dòng)作,不冒泡
});

//toggle方法
$("#button").toggle(function(){
        //第一次點(diǎn)擊時(shí)的動(dòng)作
    }, function(){
        //第二次點(diǎn)擊時(shí)的動(dòng)作
}, .../*可以放多個(gè)函數(shù),依次循環(huán)響應(yīng)*/);
事件觸發(fā)
//不能觸發(fā)addEventListener和attachEvent
//主動(dòng)觸發(fā)一個(gè)事件
$("#button").trigger("click");   //觸發(fā)所有click事件
$("#button").trigger("click.handler1");   //觸發(fā)所有click.handler1事件
$("#button").trigger(".handler1");   //觸發(fā)所有handler1命名空間的事件
$("#button").trigger("click!");   //觸發(fā)所有沒有命名空間的click事件
$("#button").trigger(event);   //在該元素上觸發(fā)和事件event一樣的事件
$("#button").trigger({type:"click", sync: true});   //觸發(fā)click事件,同步

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/97589.html

相關(guān)文章

  • 前端渲染過程的二三事

    摘要:前端渲染過程的二三事本文不會(huì)介紹整個(gè)前端渲染過程的步驟,只是記錄最近閱讀的文章的些許思考和感悟。那么現(xiàn)在我們可以明白這個(gè)問題的關(guān)鍵所在了,因?yàn)樵诖蟛糠猪撁嬷惺菗碛械模捎谄浣馕鲰樞颍敲丛谑录氨囟ㄒ呀?jīng)成功構(gòu)造樹。 前端渲染過程的二三事 本文不會(huì)介紹整個(gè)前端渲染過程的步驟,只是記錄最近閱讀的文章的些許思考和感悟。(文章地址一(系列),文章地址二) 希望大家在閱讀這篇文章之前能將上述...

    Rindia 評(píng)論0 收藏0
  • 客戶端的js js腳本的引入 js的解析過程

    摘要:瀏覽器中的瀏覽器中的通常稱為客戶端的客戶端對(duì)象是所有客戶端特性和的主要接入點(diǎn)。瀏覽器不會(huì)執(zhí)行之間的代碼中的事件處理程序當(dāng)腳本所在的文件被載入的時(shí)候。可以達(dá)到延遲腳本的執(zhí)行,直到文檔載入和解析完成,才方可操作。 web瀏覽器中的JavaScriptweb瀏覽器中的js通常稱為客戶端的JavaScript 客戶端 JavaScript window對(duì)象是所有客戶端JavaScript特性和...

    李文鵬 評(píng)論0 收藏0
  • 用PerformanceTiming來檢測(cè)頁面性能

    摘要:如果沒有前一個(gè)網(wǎng)頁,則等于屬性。該事件在網(wǎng)頁查詢本地緩存之前發(fā)生。如果使用持久連接,則返回值等同于屬性的值。返回當(dāng)前網(wǎng)頁結(jié)構(gòu)生成時(shí)即屬性變?yōu)椋约跋鄳?yīng)的事件發(fā)生時(shí)的毫秒時(shí)間戳。 window.performance.timing下的屬性 navigationStart 當(dāng)前瀏覽器窗口的前一個(gè)網(wǎng)頁關(guān)閉,發(fā)生unload事件時(shí)的Unix毫秒時(shí)間戳。如果沒有前一個(gè)網(wǎng)頁,則等于fetchSta...

    IntMain 評(píng)論0 收藏0
  • 用PerformanceTiming來檢測(cè)頁面性能

    摘要:如果沒有前一個(gè)網(wǎng)頁,則等于屬性。該事件在網(wǎng)頁查詢本地緩存之前發(fā)生。如果使用持久連接,則返回值等同于屬性的值。返回當(dāng)前網(wǎng)頁結(jié)構(gòu)生成時(shí)即屬性變?yōu)椋约跋鄳?yīng)的事件發(fā)生時(shí)的毫秒時(shí)間戳。 window.performance.timing下的屬性 navigationStart 當(dāng)前瀏覽器窗口的前一個(gè)網(wǎng)頁關(guān)閉,發(fā)生unload事件時(shí)的Unix毫秒時(shí)間戳。如果沒有前一個(gè)網(wǎng)頁,則等于fetchSta...

    pumpkin9 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<