一、事件委托

  1. 基于事件的冒泡传播机制完成
  2. 如果一个容器中很多元素都要在触发某一事件的时候做一些事情(原始方案:给元素的每一个都单独进行事件绑定),我们只需要给当前容器的这个事件行为绑定方法,这样不论是触发后代中哪一个元素的相关事件行为,由于冒泡传播机制,当前容器绑定的方法也都要被触发执行
  3. 想知道点击的是谁(根据是谁做不同的事情),只需要基于事件对象中的 ev.target 事件源获取既可。
  4. 基于事件委托实现,整体性能要比一个个的绑定方法高出50%左右
  5. 如果多元素触发,业务逻辑是属于一体的,基于事件委托来处理更加好
  6. 某些业务场景只能基于事件委托处理
  7. 在真实项目中,如果要操作的元素是基于 JS 动态绑定的,那么“相关事件行为触发做些事情”的处理操作,我们尽可能基于事件委托来处理(事件委托可以给动态绑定的元素绑定事件)

二、基于事件委托来实现某些功能

案例1

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>事件委托</title>
  6. <!-- IMPORT CSS -->
  7. <link rel="stylesheet" href="css/reset.min.css">
  8. <style>
  9. .container {
  10. margin: 20px auto;
  11. width: 200px;
  12. }
  13. .container .box {
  14. box-sizing: border-box;
  15. float: right;
  16. width: 100px;
  17. height: 35px;
  18. line-height: 35px;
  19. text-align: center;
  20. font-size: 16px;
  21. border: 1px solid #AAA;
  22. position: relative;
  23. top: 1px;
  24. }
  25. .container .detail {
  26. display: none;
  27. box-sizing: border-box;
  28. float: right;
  29. width: 200px;
  30. height: 70px;
  31. line-height: 70px;
  32. text-align: center;
  33. font-size: 14px;
  34. border: 1px solid #AAA;
  35. }
  36. </style>
  37. </head>
  38. <body>
  39. <div class="container clearfix">
  40. <div class="box"><span>购物车</span></div>
  41. <div class="detail">
  42. 暂无购物车内容
  43. </div>
  44. </div>
  45. <!-- IMPORT JS -->
  46. <script>
  47. let box = document.querySelector('.box'),
  48. detail = document.querySelector('.detail');
  49. document.onmouseover = function (ev) {
  50. let target = ev.target;
  51. if (target.tagName === "SPAN") {
  52. // 如果事件源是 SPAN,我们让其变为其父元素
  53. target = target.parentNode;
  54. }
  55. if (/^(box|detail)$/.test(target.className)) {
  56. // 如果事件源的 CLASS 是 BOX / DETAIL
  57. detail.style.display = 'block';
  58. return;
  59. }
  60. detail.style.display = 'none';
  61. }
  62. /*
  63. box.onmouseover = function (ev) {
  64. detail.style.display = 'block';
  65. }
  66. box.onmouseout = function (ev) {
  67. detail.style.display = 'none';
  68. }
  69. detail.onmouseover = function (ev) {
  70. detail.style.display = 'block';
  71. }
  72. detail.onmouseout = function (ev) {
  73. detail.style.display = 'none';
  74. }
  75. */
  76. </script>
  77. </body>
  78. </html>

案例2

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>事件委托</title>
  6. <!-- IMPORT CSS -->
  7. <link rel="stylesheet" href="css/reset.min.css">
  8. <style>
  9. .container {
  10. margin: 20px auto;
  11. width: 200px;
  12. }
  13. .container .box {
  14. box-sizing: border-box;
  15. float: right;
  16. width: 100px;
  17. height: 35px;
  18. line-height: 35px;
  19. text-align: center;
  20. font-size: 16px;
  21. border: 1px solid #AAA;
  22. position: relative;
  23. top: 1px;
  24. }
  25. .container .detail {
  26. display: none;
  27. box-sizing: border-box;
  28. float: right;
  29. width: 200px;
  30. height: 70px;
  31. line-height: 70px;
  32. text-align: center;
  33. font-size: 14px;
  34. border: 1px solid #AAA;
  35. }
  36. </style>
  37. </head>
  38. <body>
  39. <div class="container clearfix">
  40. <div class="box"><span>购物车</span></div>
  41. <div class="detail">
  42. 暂无购物车内容
  43. </div>
  44. </div>
  45. <!-- IMPORT JS -->
  46. <script>
  47. let box = document.querySelector('.box'),
  48. detail = document.querySelector('.detail');
  49. document.onclick = function (ev) {
  50. /* let target = ev.target;
  51. target.tagName === "SPAN" ? target = target.parentNode : null;
  52. if (/^box$/.test(target.className)) {
  53. // 如果是 BOX 让其显示
  54. detail.style.display = 'block';
  55. return;
  56. } */
  57. /* if (/^detail$/.test(target.className)) {
  58. //=>如果是DETAIL啥也不干
  59. return;
  60. } */
  61. // 剩下的都是隐藏
  62. detail.style.display = 'none';
  63. }
  64. box.onclick = function (ev) {
  65. // 如果是 BOX 让其显示
  66. detail.style.display = 'block';
  67. ev.stopPropagation();
  68. }
  69. detail.onclick = function (ev) {
  70. // 如果是 DETAIL 啥也不干
  71. ev.stopPropagation();
  72. }
  73. </script>
  74. </body>
  75. </html>

案例3

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>事件委托</title>
  6. <!-- IMPORT CSS -->
  7. <link rel="stylesheet" href="css/reset.min.css">
  8. <style>
  9. .box {
  10. margin: 20px auto;
  11. width: 200px;
  12. }
  13. .newsList {
  14. box-sizing: border-box;
  15. padding: 5px;
  16. border: 2px solid lightcoral;
  17. }
  18. .newsList li {
  19. line-height: 35px;
  20. border-bottom: 1px dashed #BBB;
  21. }
  22. .createBtn {
  23. box-sizing: border-box;
  24. margin-top: 10px;
  25. width: 80px;
  26. height: 30px;
  27. border: 1px solid #AAA;
  28. }
  29. </style>
  30. </head>
  31. <body>
  32. <div class="box">
  33. <ul class="newsList">
  34. <li>我是第1个LI</li>
  35. <li>我是第2个LI</li>
  36. <li>我是第3个LI</li>
  37. <li>我是第4个LI</li>
  38. <li>我是第5个LI</li>
  39. </ul>
  40. <button class="createBtn">新增</button>
  41. </div>
  42. <!-- IMPORT JS -->
  43. <script src="js/jquery.min.js"></script>
  44. <script>
  45. let $newsList = $('.newsList'),
  46. $createBtn = $('.createBtn'),
  47. count = 5;
  48. $newsList.click(function (ev) {
  49. let target = ev.target,
  50. $target = $(target);
  51. if (target.tagName === 'LI') {
  52. alert(`我是第${$target.index()+1}个LI`);
  53. }
  54. });
  55. $createBtn.click(function () {
  56. let str = ``;
  57. for (let i = 0; i < 5; i++) {
  58. count++;
  59. str += `<li>我是第${count}个LI</li>`;
  60. }
  61. $newsList.append(str);
  62. });
  63. </script>
  64. <script>
  65. /* let $newsList = $('.newsList'),
  66. $createBtn = $('.createBtn'),
  67. $lis = null;
  68. function handle() {
  69. $lis = $newsList.children('li');
  70. $lis.each(function (index, item) {
  71. $(item).click(function () {
  72. alert(`我是第${index+1}个LI`);
  73. });
  74. });
  75. }
  76. handle();
  77. let count = 5;
  78. $createBtn.click(function () {
  79. let str = ``;
  80. for (let i = 0; i < 5; i++) {
  81. count++;
  82. str += `<li>我是第${count}个LI</li>`;
  83. }
  84. $newsList.append(str);
  85. handle();
  86. }); */
  87. </script>
  88. </body>
  89. </html>

案例4

  1. // 点击页面中的每个 li,输出每个 li 里面的内容
  2. let lis = document.querySelectorAll('#list > li');
  3. // for 循环 给每个 li 绑定一个点击事件
  4. for (let i = 0; i < lis.length; i++) {
  5. lis[i].onclick = function () {
  6. console.log(this.innerText);
  7. }
  8. }
  9. // 事件委托:当遇到对一个元素中的所有子元素绑定相同的事件,并且事件触发时做的事情一样;利用事件的冒泡机制,我们把事件绑定给父元素(一般绑定给父元素,也可以绑定给更高的元素),然后根据事件触发时 事件源 e.target 判断你点击的到底是哪个元素;
  10. let list = document.querySelector('#list');
  11. list.onclick = function (e) {
  12. // ?? 怎么知道你点击的哪个li呢?
  13. // e.target 是触发事件的目标元素;
  14. console.log(e.target.innerText);
  15. };
  16. // 事件委托的性能比循环绑定性能好;