• Facebook
  • Twitter
  • RSS
月別
コツコツあつめるWeb作りのためのたね たねっぱ!Web系情報ブログ Webのお役立ちネタ配信中!

[jQuery]イベントのバブリングって何?

投稿者アイコン
2015/05/26
書いた人:
tanippa!
カテゴリ:
javascript   jQuery
52,113 views

javascriptにはイベントのバブリングという概念があります。この概念を知らないと、理解不能な状況に陥る事があるので、今回はバブリングを紹介したいと思います。

[jQuery]イベントのバブリングって何?

javascriptにはイベントのバブリングという概念があります。

この概念を知らないと、理解不能な状況に陥る事があるので、今回はバブリングを紹介したいと思います。

バブリングとは?

バブリングとは、「ある要素でイベントが発生した際に、親や祖先要素にも同じイベントが発生する事」です。

bubbling1

上の画像のように、子要素をクリックしてclickイベントが発生すると、その親要素、祖先要素でもclickイベントが発生します。

具体例

以下の例では、表示されている3つのボックスが親子関係で、それぞれにclickイベントを設定し、クリックするとアラートを出すようにしています。

ここで、ChildBox(青色のボックス)をクリックすると、ChildBoxのアラートだけでなく、ParentBoxやAncestorBoxのアラートも発生するはずです、これがイベントのバブリングの実例です。

<style>
  .rectBox {
    width : 50%;
    height: 50%;
  }
  .rectBox.root {
    width : 200px;
    height: 200px;
  }
  .rectBox.black {
    background-color: #2c3e50;
  }
  .rectBox.red {
    background-color: #c0392b;
  }
  .rectBox.blue {
    background-color: #3498db;
  }
</style>

<script>
  $(function() {
    var $ancestor = $('#AncestorBox');
    var $parent   = $('#ParentBox');
    var $child    = $('#ChildBox');

    $ancestor.on('click', function(e) {
      alert('I am ancestor');
    });

    $parent.on('click', function(e) {
      alert('I am parent');
    });

    $child.on('click', function(e) {
      alert('I am child');
    });

  });
</script>

<div id="AncestorBox" class="rectBox root black">
  <div id="ParentBox" class="rectBox red">
    <div id="ChildBox" class="rectBox blue"></div>
  </div>
</div>

stopPropagationによるバブリングのストップ

この親にもイベントが発生していくバブリングの仕組みが都合が良い場合もあるのですが、問題がある場合も度々発生します。

その場合は、stopPropagationによりバブリングをストップさせることが可能です。

bubbling2

先ほどのバブリングの例を、stopPropagationを使用してバブリングしないようにした例は以下の通りです。

<script>
  $(function() {
    var $ancestor = $('#AncestorBox');
    var $parent   = $('#ParentBox');
    var $child    = $('#ChildBox');

    $ancestor.on('click', function(e) {
      alert('I am ancestor');
      e.stopPropagation(); // 追加
    });

    $parent.on('click', function(e) {
      alert('I am parent');
      e.stopPropagation(); // 追加
    });

    $child.on('click', function(e) {
      alert('I am child');
      e.stopPropagation(); // 追加
    });

  });
</script>

今回のパターンだと、ChildBoxをクリックした場合でもアラートは1回しか発生しなかったはずです。

また、stopPropagation以外に「return false」でもバブリングをストップすることが可能です。

「return false」にはバブリングのストップ以外に、要素本来のイベントの動作(aタグの場合clickイベントに反応してリンク先に飛ぶ、等)をしないようにする効果もあるので、状況に応じて使い分けましょう。

mouseover/mouseoutとmouseenter/mouseleaveの違い

要素上にマウスが乗った・離れた際に発生するmouseover/mouseout及びmouseenter/mouseleaveイベントの違いの一つはイベントのバブリングが発生するか否かです。

mouseover/mouseoutイベントではバブリングが発生しますが、mouseenter/mouseleaveイベントはバブリングが発生しません。

具体例

実際に問題が発生する具体例として、「赤い領域にマウスが乗ったら、領域が一回点滅するような演出」を実装する必要が出てきたとします。

何も考えずにmouseoverを使用した場合、下記のような実装をしてしまうと思います。

<script>
  $(function() {
    $('#MouseWrapper .parentBox').on('mouseover', function(e) {
      $(this).animate({
        opacity: '0.5'
      }, 'fast').animate({
        opacity: '1'
      }, 'fast');
    });
  });
</script>

<style>
  #MouseWrapper .parentBox {
    width: 100px;
    height: 100px;
    padding: 50px;
    background-color: #c0392b;
  }
  #MouseWrapper .childBox {
    width: 100px;
    height: 100px;
    background-color: #2c3e50;
  }
</style>

<div id="MouseWrapper">
  <div class="parentBox">
    <div class="childBox"></div>
  </div>
</div>

この場合、赤い領域にマウスを乗せたときにちゃんと点滅しますが、何故か黒い領域にマウスが乗った時も点滅してしまいます。

この原因は、mouseover/mouseoutがバブリングを発生させるため、黒い領域に対してmouseoverイベントが発生した際に、親要素である赤い領域にもmouseoverイベントが発生してしまうためです。

他にも、mouseover/mouseoutイベントは子要素から親要素にマウスが移動した際にもmouseoverイベントが発生してしまうため、その時にも点滅してしまいます。

mouseover/mouseoutのようなマウスホバーイベントに関してバブリングが発生してほしい状況もあるかもしれませんが、どちらかというとバブリングしてしまうことによって問題が発生してしまう事が多いためmouseenter/mouseleaveを基本的には使用した方が良いと思います。

以上

バブリングは結構ややこしい概念なのですが、理解しておかないと原因がわからない挙動が発生したりして解決に時間がかかってしまうことがありそうなので、出来るだけ早く理解しておいた方がいいかと思いました。


この記事を読んだ人はこんな記事も読んでいます