亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

JavaScript自定義事件介紹

2019-11-20 22:21:12
字體:
來源:轉載
供稿:網友

很多DOM對象都有原生的事件支持,向div就有click、mouseover等事件,事件機制可以為類的設計帶來很大的靈活性,相信.net程序員深有體會。隨著web技術發展,使用JavaScript自定義對象愈發頻繁,讓自己創建的對象也有事件機制,通過事件對外通信,能夠極大提高開發效率。

簡單的事件需求

事件并不是可有可無,在某些需求下是必需的。以一個很簡單的需求為例,在web開發中Dialog很常見,每個Dialog都有一個關閉按鈕,按鈕對應Dialog的關閉方法,代碼看起來大概是這樣

復制代碼 代碼如下:

<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
        <style type="text/css" >
            .dialog
            {
                position:fixed;
                width:300px;
                height:300px;            z-index:30;
                top:50%; left:50%;
                margin-top:-200px; margin-left:-200px;
                box-shadow:2px 2px 4px #ccc;
                background-color:#f1f1f1;
                display:none;
            }

            .dialog .title
           {
                font-size:16px;
                font-weight:bold;
                color:#fff;
                padding:4px;
                background-color:#404040;
            }

            .dialog .close
           {
                width:20px;
                height:20px;
                margin:3px;
                float:right;
                cursor:pointer;
            }
        </style>
    </head>
    <body>

    <inputtype="button" value="Dialog Test" onclick="openDialog();"/>

    <divid="dlgTest" class="dialog">
        <imgclass="close" alt="" src="images/close.png">
        <divclass="title">Dialog</div>
        <divclass="content">

        </div>
    </div>

    <scripttype="text/javascript">
        function Dialog(id){
           this.id=id;
           var that=this;
            document.getElementById(id).children[0].onclick=function(){
                that.close();
            }
        }

        Dialog.prototype.show=function(){
           var dlg=document.getElementById(this.id);
            dlg.style.display='block';
            dlg=null;
        }

        Dialog.prototype.close=function(){
           var dlg=document.getElementById(this.id);
            dlg.style.display='none';
            dlg=null;
        }
   </script>

    <scripttype="text/javascript">
        function openDialog(){
           var dlg=new Dialog('dlgTest');
            dlg.show();
        }
   </script>
    </body>
<html>

這樣在點擊button的時候就可以彈出Dialog,點擊關閉按鈕的時候隱藏Dialog,看起來不錯實現了需求,但總感覺缺點兒什么,一般Dialog顯示的時候頁面還會彈出一層灰蒙蒙半透明的罩子,阻止頁面其它地方的點擊,Dialog隱藏的時候罩子去掉,頁面又能夠操作。加些代碼添個罩子。

在body頂部添加一個pagecover

<div id="pageCover" class="pageCover"></div>

為其添加style

復制代碼 代碼如下:

.pageCover
            {
                width:100%;
                height:100%;
                position:absolute;
                z-index:10;
                background-color:#666;
                opacity:0.5;
                display:none;
            }

為了打開的時候顯示page cover,需要修改openDialog方法

復制代碼 代碼如下:

function openDialog(){
            var dlg=new Dialog('dlgTest');
            document.getElementById('pageCover').style.display='block';
            dlg.show();
        }




效果很不錯的樣子,灰蒙蒙半透明的罩子在Dialog彈出后遮蓋住了頁面上的按鈕,Dialog在其之上,這時候問題來了,關閉Dialog的時候page cover仍在,沒有代碼其隱藏它,看看打開的時候怎么顯示的page cover,關閉的時候怎么隱藏行了! 還真不行,打開的代碼是頁面button按鈕的事件處理程序自己定義的,在里面添加顯示page cover的方法合情合理,但是關閉Dialog的方法是Dialog控件(雖然很簡陋,遠遠算不上是控件)自己的邏輯,和頁面無關,那修改Dialog的close方法可以嗎?也不行!有兩個原因,首先Dialog在定義的時候并不知道page cover的存在,這兩個控件之間沒有什么耦合關系,如果把隱藏page cover邏輯寫在Dialog的close方法內,那么dialog是依賴于page cover的,也就是說頁面上如果沒有page cover,dialog就會出錯。而且Dialog在定義的時候,也不知道特定頁面的page cover id,沒有辦法知道隱藏哪個div,是不是在構造Dialog時把page cover id傳入就可以了呢? 這樣兩個控件不再有依賴關系,也能夠通過id查找到page cover DIV了,但是如果用戶有的頁面需要彈出page cover,有的不需要怎么辦?

這是就事件大顯身手的時候了,修改一下dialog 對象和openDialog方法

復制代碼 代碼如下:

function Dialog(id){
            this.id=id;
            this.close_handler=null;
            var that=this;
            document.getElementById(id).children[0].onclick=function(){
                that.close();
                if(typeof that.close_handler=='function')
                {
                    that.close_handler();
                }
            }
        }

復制代碼 代碼如下:

function openDialog(){
            var dlg=new Dialog('dlgTest');
            document.getElementById('pageCover').style.display='block';

            dlg.close_handler=function(){
                document.getElementById('pageCover').style.display='none';
            }
            dlg.show();
        }

在Dialog對象內部添加一個句柄,關閉按鈕的click事件處理程序在調用close方法后判斷該句柄是否為function,是的話就調用執行該句柄。在openDialog方法中,創建Dialog對象后對句柄賦值為一隱藏page cover方法,這樣在關閉Dialog的時候就隱藏了page cover,同時沒有造成兩個控件之間的耦合。這一交互過程就是一個簡單的 定義事件――綁定事件處理程序――觸發事件的過程,DOM對象的事件,比如button的click事件也是類似原理。

高級一點的自定義事件

上面舉的小例子很簡單,遠遠不及DOM本身事件精細,這種簡單的事件處理有很多弊端

1.沒有共同性。如果在定義一個控件,還得寫一套類似的結構處理

2.事件綁定有排斥性。只能綁定了一個close事件處理程序,綁定新的會覆蓋之前綁定

3.封裝不夠完善。如果用戶不知道有個 close_handler的句柄,就沒有辦法綁定該事件,只能去查源代碼

逐個分析一下這幾個弊端,弊端一很熟悉,使用過面向對象的同學都可以輕易想到解決方法――繼承;對于弊端二則可以提供一個容器(二維數組)來統一管理所有事件;弊端三的解決需要和弊端一結合在自定義的事件管理對象中添加統一接口用于添加/刪除/觸發事件

復制代碼 代碼如下:

function EventTarget(){
            this.handlers={};
        }

        EventTarget.prototype={
            constructor:EventTarget,
            addHandler:function(type,handler){
                if(typeof this.handlers[type]=='undefined'){
                    this.handlers[type]=new Array();
                }
                this.handlers[type].push(handler);
            },
            removeHandler:function(type,handler){
                if(this.handlers[type] instanceof Array){
                    var handlers=this.handlers[type];
                    for(var i=0,len=handlers.length;i<len;i++){
                        if(handler[i]==handler){
                            handlers.splice(i,1);
                            break;
                        }
                    }
                }
            },
            trigger:function(event){
                if(!event.target){
                    event.target=this;
                }
                if(this.handlers[event.type] instanceof Array){
                    var handlers=this.handlers[event.type];
                    for(var i=0,len=handlers.length;i<len;i++){
                        handlers[i](event);
                    }
                }
            }
        }

addHandler方法用于添加事件處理程序,removeHandler方法用于移除事件處理程序,所有的事件處理程序在屬性handlers中統一存儲管理。調用trigger方法觸發一個事件,該方法接收一個至少包含type屬性的對象作為參數,觸發的時候會查找handlers屬性中對應type的事件處理程序。寫段代碼測試一下。

復制代碼 代碼如下:

function onClose(event){
            alert('message:'+event.message);
        }

        var target=new EventTarget();
        target.addHandler('close',onClose);

        //瀏覽器不能幫我們創建事件對象了,自己創建一個
        var event={
            type:'close',
            message:'Page Cover closed!'
        };

        target.trigger(event);

至此后連個弊端一解決,應用一下繼承解決第一個弊端,下面是寄生式組合繼承的核心代碼,這種繼承方式是目前公認的JavaScript最佳繼承方式

復制代碼 代碼如下:

function extend(subType,superType){
            var prototype=Object(superType.prototype);
            prototype.constructor=subType;
            subType.prototype=prototype;
        }


 最后寫成的版本就是這樣的

復制代碼 代碼如下:

<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
        <style type="text/css" >
            html,body
            {
                height:100%;
                width:100%;
                padding:0;
                margin:0;
            }

            .dialog
            {
                position:fixed;
                width:300px;
                height:300px;
                top:50%;
                left:50%;
                margin-top:-200px;
                margin-left:-200px;
                box-shadow:2px 2px 4px #ccc;
                background-color:#f1f1f1;
                z-index:30;
                display:none;
            }

            .dialog .title
            {
                font-size:16px;
                font-weight:bold;
                color:#fff;
                padding:4px;
                background-color:#404040;
            }

            .dialog .close
            {
                width:20px;
                height:20px;
                margin:3px;
                float:right;
                cursor:pointer;
            }

            .pageCover
            {
                width:100%;
                height:100%;
                position:absolute;
                z-index:10;
                background-color:#666;
                opacity:0.5;
                display:none;
            }
        </style>
    </head>
    <body>
    <div id="pageCover" class="pageCover"></div>

    <input type="button" value="Dialog Test" onclick="openDialog();"/>

    <div id="dlgTest" class="dialog">
        <img class="close" alt="" src="images/close.png">
        <div class="title">Dialog</div>
        <div class="content">

        </div>
    </div>

    <script type="text/javascript">           
        function EventTarget(){
            this.handlers={};
        }

        EventTarget.prototype={
            constructor:EventTarget,
            addHandler:function(type,handler){
                if(typeof this.handlers[type]=='undefined'){
                    this.handlers[type]=new Array();
                }
                this.handlers[type].push(handler);
            },
            removeHandler:function(type,handler){
                if(this.handlers[type] instanceof Array){
                    var handlers=this.handlers[type];
                    for(var i=0,len=handlers.length;i<len;i++){
                        if(handler[i]==handler){
                            handlers.splice(i,1);
                            break;
                        }
                    }
                }
            },
            trigger:function(event){
                if(!event.target){
                    event.target=this;
                }
                if(this.handlers[event.type] instanceof Array){
                    var handlers=this.handlers[event.type];
                    for(var i=0,len=handlers.length;i<len;i++){
                        handlers[i](event);
                    }
                }
            }
        }
        </script>

    <script type="text/javascript">
        function extend(subType,superType){
            var prototype=Object(superType.prototype);
            prototype.constructor=subType;
            subType.prototype=prototype;
        }
    </script>

    <script type="text/javascript">
        function Dialog(id){
            EventTarget.call(this)
            this.id=id;
            var that=this;
            document.getElementById(id).children[0].onclick=function(){
                that.close();
            }
        }

        extend(Dialog,EventTarget);

       
        Dialog.prototype.show=function(){
            var dlg=document.getElementById(this.id);
            dlg.style.display='block';
            dlg=null;
        }

        Dialog.prototype.close=function(){
            var dlg=document.getElementById(this.id);
            dlg.style.display='none';
            dlg=null;
            this.trigger({type:'close'});
        }
    </script>

    <script type="text/javascript">
        function openDialog(){       
            var dlg=new Dialog('dlgTest');

            dlg.addHandler('close',function(){
                document.getElementById('pageCover').style.display='none';
            });

            document.getElementById('pageCover').style.display='block';
            dlg.show();
        }
    </script>
    </body>
<html>

最后

這樣解決了幾個弊端看起來就完美多了,其實可以把打開Dialog顯示page cover也寫成類似關閉時事件的方式了。當代碼中存在多個部分在特定時刻相互交互的情況下,自定義事件就非常有用了。如果每個對象都有其它對象的引用,那么整個代碼高度耦合,對象改動會影響其它對象,維護起來困難重重。自定義事件使對象解耦,功能隔絕,這樣對象之間實現了高聚合。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本久久久久久| 亚洲男人av电影| 97人洗澡人人免费公开视频碰碰碰| 91久久夜色精品国产网站| 欧美体内谢she精2性欧美| 久久精品美女视频网站| 欧美巨乳美女视频| 亚洲xxxx3d| 欧美午夜美女看片| 91国内精品久久| 欧美激情videos| 成人国产精品久久久久久亚洲| 亚洲激情 国产| 一本久久综合亚洲鲁鲁| 高清欧美电影在线| 日韩亚洲精品电影| 欧美视频13p| 亚洲男人天堂古典| 草民午夜欧美限制a级福利片| 欧美激情欧美激情在线五月| 亚洲欧美综合另类中字| 日韩av中文字幕在线播放| 国产视频欧美视频| 日韩hd视频在线观看| 成人网页在线免费观看| 欧美激情亚洲视频| 91av在线免费观看视频| 狠狠躁天天躁日日躁欧美| 国产+成+人+亚洲欧洲| 久久激情视频久久| 国产精品第8页| 亚洲wwwav| 日韩欧美aⅴ综合网站发布| 成人激情在线播放| 日韩电影在线观看永久视频免费网站| 亚洲成人网久久久| 欧美日韩激情网| 欧美精品国产精品日韩精品| 91精品国产高清自在线看超| 92裸体在线视频网站| 91热福利电影| 色偷偷偷亚洲综合网另类| 91精品国产91久久久久久不卡| 色综合久久久久久中文网| 国产欧美va欧美va香蕉在线| 国内免费久久久久久久久久久| 欧美综合在线观看| 国产女人精品视频| 5566日本婷婷色中文字幕97| 国产一区二区在线免费| 一区二区三区天堂av| 国产精品伦子伦免费视频| 91在线观看免费网站| 亚洲欧美中文在线视频| 国产日韩在线播放| 成人深夜直播免费观看| 国产不卡在线观看| 欧美小视频在线| 欧美激情一区二区久久久| 日韩一区二区在线视频| 国产亚洲精品成人av久久ww| 日韩精品在线视频观看| 欧美一乱一性一交一视频| 欧美裸体视频网站| 欧美成人网在线| 91精品国产高清久久久久久91| 欧美成在线观看| 欧美理论在线观看| 国产成人精品免高潮费视频| 久久精品成人欧美大片| 色综合伊人色综合网| 精品久久久久久亚洲国产300| 97在线视频精品| 亚洲春色另类小说| 欧美成在线视频| 欧美在线www| 日本精品久久电影| 色久欧美在线视频观看| 色综合亚洲精品激情狠狠| 成人久久精品视频| 91国内揄拍国内精品对白| 国产精品嫩草影院一区二区| 日韩欧美中文免费| 国产在线精品成人一区二区三区| 中文字幕自拍vr一区二区三区| 日韩午夜在线视频| 国产亚洲精品美女久久久| 亚洲午夜久久久久久久| 91久久在线播放| 精品日本高清在线播放| 久久久久久亚洲精品中文字幕| 日韩在线观看免费av| 在线观看国产精品日韩av| 亚洲精品在线观看www| 91久久精品国产91久久性色| 亚洲国产97在线精品一区| 按摩亚洲人久久| 秋霞午夜一区二区| 青青久久aⅴ北条麻妃| 26uuu另类亚洲欧美日本一| 欧美极品少妇xxxxⅹ喷水| 欧美精品激情视频| 一区二区国产精品视频| 91精品视频免费观看| 国产成人精品免高潮费视频| 国产丝袜一区二区三区免费视频| 亚洲欧美视频在线| 国产精品久久久精品| 亚洲精品美女久久久久| 欧美精品videos| 91精品国产高清久久久久久91| 97在线观看免费高清| 久久国产精品久久国产精品| 91最新国产视频| 97超视频免费观看| 最近2019年日本中文免费字幕| 欧美性猛交丰臀xxxxx网站| 国产精品jvid在线观看蜜臀| 亚洲精品有码在线| 色多多国产成人永久免费网站| 亚洲国语精品自产拍在线观看| 亚洲免费人成在线视频观看| 亚洲免费福利视频| 日韩二区三区在线| 国产免费一区二区三区香蕉精| 久久亚洲精品中文字幕冲田杏梨| 伊人一区二区三区久久精品| 国产精品99久久久久久久久久久久| 91精品久久久久久久久| 亚洲人成绝费网站色www| 日韩电影中文字幕| 亚洲国产日韩欧美在线动漫| 九九精品在线播放| 8x海外华人永久免费日韩内陆视频| 欧美激情一区二区三级高清视频| 成人在线一区二区| 国产精品一区=区| 国产欧美日韩最新| 国产精品精品视频一区二区三区| 激情亚洲一区二区三区四区| 日韩69视频在线观看| 国产在线观看不卡| 亚洲人成在线免费观看| 日韩精品亚洲精品| 日韩av免费观影| 黑人狂躁日本妞一区二区三区| 综合国产在线视频| 成人激情视频免费在线| 26uuu久久噜噜噜噜| 92国产精品久久久久首页| 美日韩丰满少妇在线观看| 欧美激情亚洲自拍| 国产午夜精品久久久| 中文字幕成人在线| 成人免费观看网址| 亚洲欧美中文日韩在线v日本| 欧美日韩加勒比精品一区| 国产精品国产三级国产专播精品人| 精品亚洲一区二区三区在线播放| 国产精品久久久久久网站| 国产欧美亚洲视频| 欧美精品日韩三级| 国产精品视频一区二区高潮| 精品一区精品二区|