Javascriptイベントデリゲーションの詳しい説明

巴扎黑
リリース: 2017-07-24 16:02:48
オリジナル
1111 人が閲覧しました

原因:

1. これは、フロントエンドの面接によくある質問です。

2. 実際、私はまだそれを理解していません。これは準備のために書いたものです。もう 1 つは、それを知っていても理由が​​わからない他の友人に参考にするためです。

では、イベント委任とは何ですか?高度な JavaScript プログラミングの観点からは、イベント プロキシと呼ばれる名前もあります。イベント デリゲーションは、イベント バブリングを使用して、イベント ハンドラーを 1 つだけ指定することによって、特定の種類のすべてのイベントを管理します。では、これは何を意味するのでしょうか?インターネットの専門家は、イベントの委任について話すときに、基本的に同じ例を使用します。つまり、この現象を説明するために、この例が本当に適切であることがわかりました。仏陀にお供えする花をいくつか摘んでみましょう。イベントの委任の原則を詳しく見てみましょう:

月曜日に 3 人の同僚が速達で配達される予定です。速達の署名方法は 2 つあります。1 つは会社の玄関で 3 人で速達を待ってもらう方法、もう 1 つは受付担当者に代理で署名を依頼する方法です。実際、私たちは主に委託ソリューションを使用しています (会社は、速達を待っているだけでドアに立っている多くの従業員を容認しません)。フロントデスクの MM は速達を受け取ると、受取人が誰であるかを判断し、受取人の要件に従って署名し、代わりに代金を支払います。このソリューションのもう 1 つの利点は、新入社員が (人数に関係なく) 会社に来ても、フロント デスクの MM が新入社員に送られた速達便を確認し、新入社員に代わって署名することです。

ここには実際には 2 つのレベルの意味があります:

まず、フロントデスクの同僚が署名できるようになります。つまり、プログラム内の既存の dom ノードにイベントがあります。

次に、新しい従業員も署名できます。これはフロントデスク MM によって署名されています。つまり、プログラムに新しく追加された dom ノードにもイベントがあります。

イベント委任を使用する理由:

一般的に言えば、DOM にはイベント ハンドラーが必要なので、イベント ハンドラーを直接設定するだけですが、イベント ハンドラーを追加する必要がある DOM が多数ある場合はどうなるでしょうか。たとえば、100 個の li があり、各 li に同じクリック イベントがあるとします。おそらく、for ループ メソッドを使用してすべての li を走査し、それらにイベントを追加するとどうなるでしょうか。

JavaScript では、ページに追加されるイベント ハンドラーの数は、ページの全体的な実行パフォーマンスに直接関係します。これは、dom ノードと常にやり取りする必要があるため、dom へのアクセス回数が増えると、ブラウザの再描画とリフローの回数が増えると、ページ全体のインタラクティブな準備時間が長くなります。このため、イベント委任を使用する場合、DOM 操作を減らすことが重要になります。内部では、DOM との操作は 1 回だけ行う必要があるため、DOM との操作の数が大幅に削減され、パフォーマンスが向上します

各関数はオブジェクトであり、そのオブジェクトがメモリを占有します。オブジェクトの数が増えると、占有されるメモリも増えます (メモリ不足は欠陥です、笑)。イベント委任を使用すると、その親のオブジェクトに対してのみ操作できるようになります (親が 1 つだけの場合)。これにより、必要なメモリ空間が 1 つだけになり、当然のことながら大幅に節約されます。パフォーマンスが向上します。

イベント委任の原理:

イベント委任は、イベントのバブリング原理を使用して実装されます。 イベントのバブリングとは何ですか?つまり、イベントは最も深いノードから始まり、徐々に上に伝播します。たとえば、ページ上にこのようなノード ツリーがあり、div>ul>li>a; にクリック イベントを追加するとします。一番内側の a の場合、このイベントはレイヤーごとに実行されます。実行順序は a>li>ul>div です。次に、一番外側の div にクリック イベントを追加します。 、li、および内部のクリック イベントは、最も外側の div にバブルされるため、トリガーされます。これは、親に代わってイベントを実行することを委任します。

イベント委任の実装方法:

ついにこの記事の核心部分に到達しました、笑、イベント委任の方法を紹介する前に、一般的な方法の例を見てみましょう:

子ノードは同じものを実装しますfunction:

ログイン後にコピー
        
  • 111
  •     
  • 222
  •     
  • 333
  •     
  • 444

関数を実装するには、li をクリックすると、123 がポップアップします:

window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;iJavascriptイベントデリゲーションの詳しい説明
ログイン後にコピー
Javascriptイベントデリゲーションの詳しい説明 上記のコードの意味は、多くの人が非常に単純だと思います。このように実装しました。dom がいくつあるか見てみましょう。操作するには、最初に ul を見つけてから li を移動し、次に li をクリックして、最後の操作を実行する前にターゲット li の位置を再度見つける必要があります。クリックするたびに li を見つける必要があります
次に、イベント委任を使用します。このようにするとどうなりますか?

りー

 

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发,不怕,我们有绝招:

Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题):

Javascriptイベントデリゲーションの詳しい説明

window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
         alert(123);
         alert(target.innerHTML);
    }
  }
}

Javascriptイベントデリゲーションの詳しい説明

 

这样改下就只有点击li会触发事件了,且每次只执行一次dom操作,如果li数量很多的话,将大大减少dom的操作,优化的性能可想而知!

 

上面的例子是说li操作的是同样的效果,要是每个li被点击的效果都不一样,那么用事件委托还有用吗?

                                        
ログイン後にコピー
Javascriptイベントデリゲーションの詳しい説明
window.onload = function(){
            var Add = document.getElementById("add");
            var Remove = document.getElementById("remove");
            var Move = document.getElementById("move");
            var Select = document.getElementById("select");
            
            Add.onclick = function(){
                alert('添加');
            };
            Remove.onclick = function(){
                alert('删除');
            };
            Move.onclick = function(){
                alert('移动');
            };
            Select.onclick = function(){
                alert('选择');
            }
            
        }
ログイン後にコピー
Javascriptイベントデリゲーションの詳しい説明

 

上面实现的效果我就不多说了,很简单,4个按钮,点击每一个做不同的操作,那么至少需要4次dom操作,如果用事件委托,能进行优化吗?

Javascriptイベントデリゲーションの詳しい説明
window.onload = function(){
            var oBox = document.getElementById("box");
            oBox.onclick = function (ev) {
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLocaleLowerCase() == 'input'){
                    switch(target.id){
                        case 'add' :
                            alert('添加');
                            break;
                        case 'remove' :
                            alert('删除');
                            break;
                        case 'move' :
                            alert('移动');
                            break;
                        case 'select' :
                            alert('选择');
                            break;
                    }
                }
            }
            
        }
ログイン後にコピー
Javascriptイベントデリゲーションの詳しい説明

 

用事件委托就可以只用一次dom操作就能完成所有的效果,比上面的性能肯定是要好一些的 

 

 现在讲的都是document加载完成的现有dom节点下的操作,那么如果是新增的节点,新增的节点会有事件吗?也就是说,一个新员工来了,他能收到快递吗?

看一下正常的添加节点的方法:

Javascriptイベントデリゲーションの詳しい説明

    
ログイン後にコピー
            
  • 111
  •         
  • 222
  •         
  • 333
  •         
  • 444
  •     
Javascriptイベントデリゲーションの詳しい説明

 

现在是移入li,li变红,移出li,li变白,这么一个效果,然后点击按钮,可以向ul中添加一个li子节点

 

Javascriptイベントデリゲーションの詳しい説明
window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            
            //鼠标移入变红,移出变白
            for(var i=0; i
Javascriptイベントデリゲーションの詳しい説明
ログイン後にコピー

 

这是一般的做法,但是你会发现,新增的li是没有事件的,说明添加子节点的时候,事件没有一起添加进去,这不是我们想要的结果,那怎么做呢?一般的解决方案会是这样,将for循环用一个函数包起来,命名为mHover,如下:

Javascriptイベントデリゲーションの詳しい説明
window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            
            function mHover () {
                //鼠标移入变红,移出变白
                for(var i=0; i
Javascriptイベントデリゲーションの詳しい説明
ログイン後にコピー

 

虽然功能实现了,看着还挺好,但实际上无疑是又增加了一个dom操作,在优化性能方面是不可取的,那么有事件委托的方式,能做到优化吗?

Javascriptイベントデリゲーションの詳しい説明
window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            
            //事件委托,添加的子元素也有事件
            oUl.onmouseover = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "red";
                }
                
            };
            oUl.onmouseout = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#fff";
                }
                
            };
            
            //添加新节点
            oBtn.onclick = function(){
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111*num;
                oUl.appendChild(oLi);
            };
        }
ログイン後にコピー
Javascriptイベントデリゲーションの詳しい説明

 

看,上面是用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。

 

--------------------------------------------------华丽的分割线-------------- -----------------------------------------------------------------------------------------------------

在这里先感谢一下@苍茫大地NV 的提问,提的问题非常好!

以上がJavascriptイベントデリゲーションの詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!