如何在jQuery中formalize/organize海量的eventHandler?

How to formalize/organize a massive amount of eventHandler in jQuery?

我是 JavaScript 的新手,不知道如何编写大量事件处理程序的代码,例如 mouseover/mouseout

假设我必须在页面上键入元素。每个元素都应该触发一个特定的事件。我是否必须为每个元素编写每个函数的代码,或者有一种方法可以将其抽象化,以便它们由另一个函数生成。

这是一个包含两个元素的两个列表的示例,但是我考虑的是每个列表有数百个元素的情况。

<!-- List 1 -->
    <div id="a">the A</div>
    <div id="b">the B</div>
    <!-- List 2 -->
    <div id="i">the I</div>
    <div id="j">the J</div>

    <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
    <script>
    $( '#a' )
        .mouseover(function() {
            $( '#i' ).css("color", "red")
        })
        .mouseout(function() {
            $( '#i' ).css("color", "black")
        })

    $( '#b')
        .mouseover(function() {
            $( '#j' ).css("color", "red")
        })
        .mouseout(function() {
            $( '#j' ).css("color", "black")
        })

    $( '#j')
        .mouseover(function() {
            $( '#a' ).css("color", "red")
            $( '#i' ).css("color", "red")
        })
        .mouseout(function() {
            $( '#a' ).css("color", "black")
            $( '#i' ).css("color", "black")
        })
    </script>

我怎样才能简单地使用这样的数组来表示我想要的交互:

var todo = [
    [a, [i]],
    [b, [j]],
    [j, [a, i]]
]

还有一个可以同时实现它们的函数:

makeAllMouseover(todo)

我想我遗漏了关于 html/js 的一些非常明显的东西,但我无法弄清楚 what/why...

您可以使用以下代码段中的第一个将您想要的效果单独应用到每个元素,或者,您可以使用第二个代码段,它会自动为您执行此操作:

第一个代码段: (应用于第一个)

/* ----- JavaScript ----- */
function change(selector) {
  var affected, hoverColor;
  switch (selector) {
    case "#a":
      affected = ["#i"];
      hoverColor = "red";
      break;
    case "#b":
      affected = ["#j"];
      hoverColor = "blue";
      break;
    case "#j":
      affected = ["#a", "#i"];
      hoverColor = "yellow";
      break;
  }

  $(selector).hover(function() {
    for (var i = 0; i < affected.length; i++) $(affected[i]).css("color", hoverColor)
  }, function() {
    for (var i = 0; i < affected.length; i++) $(affected[i]).css("color", "black")
  });
}

/* APPLY THE EFFECT */
change("#a");
<!----- HTML ----->
<!-- List 1 -->
<div id="a">the A</div>
<div id="b">the B</div>
<!-- List 2 -->
<div id="i">the I</div>
<div id="j">the J</div>

<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>

第二个片段: (应用于每个人)

/* ----- JavaScript ----- */
["#a", "#b", "#j"].forEach(function(each) {
  (function(selector) {
    var affected, hoverColor;
    switch (selector) {
      case "#a":
        affected = ["#i"];
        hoverColor = "red";
        break;
      case "#b":
        affected = ["#j"];
        hoverColor = "blue";
        break;
      case "#j":
        affected = ["#a", "#i"];
        hoverColor = "yellow";
        break;
    }

    $(selector).hover(function() {
      for (var i = 0; i < affected.length; i++) $(affected[i]).css("color", hoverColor)
    }, function() {
      for (var i = 0; i < affected.length; i++) $(affected[i]).css("color", "black")
    });
  })(each);
});
<!----- HTML ----->
<!-- List 1 -->
<div id="a">the A</div>
<div id="b">the B</div>
<!-- List 2 -->
<div id="i">the I</div>
<div id="j">the J</div>

<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>

第二个脚本的较短代码:

/* ----- JavaScript ----- */
["#a", "#b", "#j"].forEach(function(each) {
  (function(s) {
    var
      aff = (s === "#a") ? ["#i"] : ((s === "#b") ? ["#j"] : ((s === "#j") ? ["#a", "#i"] : "")),
      hovColor = (s === "#a") ? "red" : ((s === "#b") ? "blue" : ((s === "#j") ? "yellow" : "")),
      unhover;

    $(s).hover(changeColor, changeColor);
    
    function changeColor () {
      for (var i = 0; i < aff.length; i++) $(aff[i]).css("color", (unhover) ? "black" : hovColor);
      unhover = !unhover;
    }
  })(each);
});
<!----- HTML ----->
<!-- List 1 -->
<div id="a">the A</div>
<div id="b">the B</div>
<!-- List 2 -->
<div id="i">the I</div>
<div id="j">the J</div>

<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>


备注:

  1. 对于 affected 变量,我使用数组 (affected = ["#i"])而不是字符串(affected = "#i"),这样我们就可以利用length 属性 的数组,并使用 for 循环来确保第三种情况达到预期效果

  2. 而不是使用 mouseovermouseout,您可以使用 hover 有两个参数,都是函数并且对应于 mouseovermouseout 分别(hover(mouseover, mouseout)).

  3. switch 语句是硬编码的,这意味着如果要添加更多元素,则必须为每个元素创建一个新案例并且,还要在 id 之前的数组中添加要使用 hover 的每个元素 forEach 在片段的开头。

只要你的 todo 数组不改变格式,下面的内容应该可以动态地处理你扔给它的任何东西。

var todo = [
  ['a', ['i']],
  ['b', ['j']],
  ['j', ['a', 'i']]
];

todo.forEach(function(el) { // Loop through the array
  $('#' + el[0]).hover(function() { // MouseIn 
    $('#' + el[1].join(', #')).addClass('makeRed'); // Stringify the targets to add the class
  }, function() { // MouseOut
    $('#' + el[1].join(', #')).removeClass('makeRed'); // Stringify the targets to remove the class
  });
});
div {
  border-bottom: 1px solid black;
  color: black;  
}

.makeRed {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="listContainer">
<!-- List 1 -->
<div id="a">the A</div>
<div id="b">the B</div>
<!-- List 2 -->
<div id="i">the I</div>
<div id="j">the J</div>

JamieC 提出了关于不使用 ID 来定位事件处理程序的正确观点。我建议更进一步并使用 event delegation 这样只有一个监听器被添加到页面,而不是每个元素的多个监听器:

var todo = [
  ['a', ['i']],
  ['b', ['j']],
  ['j', ['a', 'i']]
];

function hoverText(id, isIn) {
  // Filter the array to just contain the one we've clicked
  var elements = todo.filter(function(value) {
    return id === value[0]
  })[0];

  // If the array is found, add/remove the class to/from the target elements
  if (elements) {
    elements = $('#' + elements[1].join(', #'));
     if (isIn) {
       elements.addClass('makeRed');
     } else {
       elements.removeClass('makeRed');
     }
   }
}

/**
 * Add event listener to the nearest element that surrounds all list items
 * Delegate the action to the list item(s).
 */
$('.listContainer').on('mouseenter', '.listItem', function(event) {
  hoverText(event.target.id, true)
}).on('mouseleave', '.listItem', function(event) {
  hoverText(event.target.id, false)
});
.listContainer .listItem {
  border-bottom: 1px solid black;
  color: black;
}
.listContainer .listItem.makeRed {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="listContainer">
  <!-- List 1 -->
  <div class="listItem" id="a">the A</div>
  <div class="listItem" id="b">the B</div>
  <!-- List 2 -->
  <div class="listItem" id="i">the I</div>
  <div class="listItem" id="j">the J</div>
</div>

我会首先不使用 id 来定位事件处理程序 - 使用共享 class,我也不会使用 array/map 来表示您的交互。使用一些 data-* 属性来表示元素之间的关联要容易得多

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- List 1 -->
    <div id="a" class="mouse-action" data-highlight="#i">the A</div>
    <div id="b" class="mouse-action" data-highlight="#j">the B</div>
    <!-- List 2 -->
    <div id="i" class="mouse-action">the I</div>
    <div id="j" class="mouse-action" data-highlight="#a, #b">the J</div>

    <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
    <script>
      $(".mouse-action")
        .mouseover(function() {
            $( $(this).data("highlight") ).css("color", "red")
        })
        .mouseout(function() {
            $( $(this).data("highlight") ).css("color", "black")
        })
    </script>