【问题标题】:Passing <select> as jQuery event's parameter传递 <select> 作为 jQuery 事件的参数
【发布时间】:2017-11-15 18:42:13
【问题描述】:

当我将 &lt;select&gt; 元素作为参数传递给 jQuery 事件(使用触发器)时,事件处理程序仅获取该 &lt;select&gt; 的第一个 &lt;option&gt;。这是一个错误还是我做错了什么?

我写了一个简单的片段来演示它。 请在控制台中查看输出。

var onInputMounted = function(e, data) {
  console.log("mounted", data);
};

var onInputUnmounted = function(e, data) {
  console.log("unmounted", data);
};

var observer = new MutationObserver(function(changes) {
  changes.forEach(function(element, index) {
    var allChangedNodes = [];
    var allChangedInputs = [];

    if (element.type === "childList") {
      // get all changed (added/removed) HTML nodes
      if (element.addedNodes.length > 0) {
        allChangedNodes = Array.prototype.slice
          .call(element.addedNodes)
          .map(function(e, i) {
            return {
              node: e,
              event: "mounted"
            };
          });
      } else if (element.removedNodes.length > 0) {
        allChangedNodes = Array.prototype.slice
          .call(element.removedNodes)
          .map(function(e, i) {
            return {
              node: e,
              event: "unmounted"
            };
          });
      }

      // get all changed (added/removed) HTML :input fields
      allChangedInputs = allChangedNodes
        .map(function(e) {
          return $(e.node)
            .find(":input")
            .addBack(":input")
            .map(function(i, input) {
              return {
                input: input,
                event: e.event
              };
            });
        })
        .reduce(function(arrLike1, arrLike2) {
          var arr1 = Array.prototype.slice.call(arrLike1);
          var arr2 = Array.prototype.slice.call(arrLike2);
          return arr1.concat(arr2);
        });
    }

    // trigger the corresponding event: mounted (for added inputs), unmounted (for removed ones)
    for (var i = 0; i < allChangedInputs.length; i++) {
      console.log("trigger", allChangedInputs[i]);
      $("#container").trigger(
        allChangedInputs[i].event,
        allChangedInputs[i].input
      );
    }
  });
});

// register events
$("#container").on("mounted", onInputMounted);
$("#container").on("unmounted", onInputUnmounted);

// observe changes on DOM
observer.observe($("#container")[0], {
  childList: true,
  subtree: true,
  attributes: false,
  characterData: false
});

// append a div with two inputs
$("#container").append(
  '<div><input id="name" /><select id="gender"><option value="male">male</option><option value="female">female</option></select></div>'
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container"></div>

我像这样触发“挂载”和“卸载”事件:

$("#container").trigger(
   allChangedInputs[i].event,
   allChangedInputs[i].input
);

其中allChangedInputs[i].input 是 HTML 输入已添加(挂载)/删除(卸载)

问题是当这个输入是&lt;select&gt; 时,事件处理程序只接收&lt;option&gt;。有什么线索吗?

谢谢!

【问题讨论】:

    标签: javascript jquery events select parameters


    【解决方案1】:

    这是因为trigger 方法接受一个数组或一个对象,它试图将allChangedInputs[i].input 转换为一个数组。

    只需将其转换为

    [allChangedInputs[i].input]
    

    解决您的问题,请参阅下面的演示

    var onInputMounted = function(e, data) {
      console.log("mounted", data);
    };
    
    var onInputUnmounted = function(e, data) {
      console.log("unmounted", data);
    };
    
    var observer = new MutationObserver(function(changes) {
      changes.forEach(function(element, index) {
        var allChangedNodes = [];
        var allChangedInputs = [];
    
        if (element.type === "childList") {
          // get all changed (added/removed) HTML nodes
          if (element.addedNodes.length > 0) {
            allChangedNodes = Array.prototype.slice
              .call(element.addedNodes)
              .map(function(e, i) {
                return {
                  node: e,
                  event: "mounted"
                };
              });
          } else if (element.removedNodes.length > 0) {
            allChangedNodes = Array.prototype.slice
              .call(element.removedNodes)
              .map(function(e, i) {
                return {
                  node: e,
                  event: "unmounted"
                };
              });
          }
    
          // get all changed (added/removed) HTML :input fields
          allChangedInputs = allChangedNodes
            .map(function(e) {
              return $(e.node)
                .find(":input")
                .addBack(":input")
                .map(function(i, input) {
                  return {
                    input: input,
                    event: e.event
                  };
                });
            })
            .reduce(function(arrLike1, arrLike2) {
              var arr1 = Array.prototype.slice.call(arrLike1);
              var arr2 = Array.prototype.slice.call(arrLike2);
              return arr1.concat(arr2);
            });
        }
    
        // trigger the corresponding event: mounted (for added inputs), unmounted (for removed ones)
        for (var i = 0; i < allChangedInputs.length; i++) {
          console.log("trigger", allChangedInputs[i]);
          $("#container").trigger(
            allChangedInputs[i].event,
            [allChangedInputs[i].input] //this line
          );
        }
      });
    });
    
    // register events
    $("#container").on("mounted", onInputMounted);
    $("#container").on("unmounted", onInputUnmounted);
    
    // observe changes on DOM
    observer.observe($("#container")[0], {
      childList: true,
      subtree: true,
      attributes: false,
      characterData: false
    });
    
    // append a div with two inputs
    $("#container").append(
      '<div><input id="name" /><select id="gender"><option value="male">male</option><option value="female">female</option></select></div>'
    );
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="container"></div>

    【讨论】:

    • 好的,这是有道理的,因此我将答案标记为正确。但我还有后续。我做了一些研究,发现 jQuery 使用它的 makeArray 函数从一个对象构建一个数组。但是为什么当我传递一个 HTML 的数组,它是参数!?
    • @muhanerd 你能否指出一个来源,说 jQuery 使用其 makeArray 函数从对象构建数组 以防触发?
    • 另外,如果你这样做allChangedInputs[i].input[0],它会显示option
    • 好吧,我想我错误地表述了这句话。我的意思是:根据您的陈述 它正在尝试将 allChangedInputs[i].input 转换为数组 我考虑了执行此操作的可能方法并尝试了它们:1)将参数包装在 [ ],或 2) .toArray() 但这仅在参数已经是 jQuery 对象时才有效,或者 3) makeArray() 会导致我遇到的问题。所以我假设(未发现)jQuery 使用 makeArray 将参数转换为数组。你认为 jQuery 以不同的方式做到这一点吗?
    • @muhanerd 我浏览了触发器的文档,没有提到 makeArray。 makeArray 也只是[].slice.call(array-link) 的简写。所以,我假设这样的事情会在幕后发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 2010-10-04
    • 2014-08-15
    • 2010-10-09
    • 2013-01-27
    • 2020-07-27
    • 1970-01-01
    相关资源
    最近更新 更多