动态创建元素的jQuery“on create”事件

IT技术 javascript jquery combobox
2021-01-28 07:44:39

我需要能够动态创建<select>元素并将其转换为 jQuery .combobox()这应该是元素创建事件,而不是一些“点击”事件,在这种情况下我可以只使用 jQuery .on()

那么这样的东西存在吗?

$(document).on("create", "select", function() {
    $(this).combobox();
}

我不愿意使用livequery,因为它已经过时了。

更新提到的选择/组合框通过 ajax 加载到 jQuery 颜色框(模态窗口)中,因此问题 - 我只能使用 colorbox 启动组合框onComplete,但是在更改一个组合框时必须动态创建另一个选择/组合框,因此我需要一个更通用的方法来检测元素的创建(select在这种情况下)。

UPDATE2尝试进一步解释问题 - 我select/combobox递归创建了元素,内部也有很多启动代码.combobox(),因此如果我使用经典方法,如@bipen's answer,我的代码会膨胀到疯狂的水平。希望这能更好地解释问题。

UPDATE3谢谢大家,我现在明白,由于弃用DOMNodeInsertedDOM 突变中存在空白,并且没有解决此问题的方法。我只需要重新考虑我的申请。

6个回答

您可以通过onDOMNodeInserted事件获取代码将其添加到文档时的事件。

$('body').on('DOMNodeInserted', 'select', function () {
      //$(this).combobox();
});

$('<select>').appendTo('body');
$('<select>').appendTo('body');

在这里摆弄:http : //jsfiddle.net/Codesleuth/qLAB2/3/

编辑:阅读后我只需要仔细检查DOMNodeInserted不会在浏览器中引起问题。这个2010 年的问题表明 IE 不支持该事件,因此如果可以,请对其进行测试。

请参阅此处:[链接] 警告!本规范中定义了 DOMNodeInserted 事件类型以供参考和完整性,但本规范不赞成使用此事件类型。

由于您尝试过它不在您的问题中,因此我会说这是不公平的投票。无论如何,我在这里帮不了你。
2021-04-03 07:44:39
on('DOMNodeInserted'在发布这个问题之前已经试过了这显然没有用。
2021-04-06 07:44:39
.delegatejQuery 1.7 版没有被弃用并被.on?
2021-04-08 07:44:39
是的,你说得对。我会修改这个答案,但老实说,我不确定你是否应该使用它,因为DOMNodeInserted它现在已被弃用。
2021-04-11 07:44:39

正如其他几个答案中提到的,突变事件已被弃用,因此您应该改用MutationObserver由于还没有人提供任何详细信息,所以在这里......

基本 JavaScript API

MutationObserver 的 API 相当简单。它不像突变事件那么简单,但它仍然可以。

function callback(records) {
  records.forEach(function (record) {
    var list = record.addedNodes;
    var i = list.length - 1;
    
	for ( ; i > -1; i-- ) {
	  if (list[i].nodeName === 'SELECT') {
	    // Insert code here...
	    console.log(list[i]);
	  }
	}
  });
}

var observer = new MutationObserver(callback);

var targetNode = document.body;

observer.observe(targetNode, { childList: true, subtree: true });
<script>
  // For testing
  setTimeout(function() {
    var $el = document.createElement('select');
    document.body.appendChild($el);
  }, 500);
</script>

让我们分解一下。

var observer = new MutationObserver(callback);

这将创建观察者。观察者还没有看到任何东西;这正是事件侦听器被附加的地方。

observer.observe(targetNode, { childList: true, subtree: true });

这使得观察者启动。第一个参数是观察者将观察变化的节点。第二个参数是关注什么选项

  • childList 意味着我想观察被添加或删除的子元素。
  • subtree是一个修饰符,它扩展 childList到监视此元素子树中任何位置的更改(否则,它只会直接查看 中的更改targetNode)。

其他两个主要选择,除了childListattributescharacterData,这意味着对他们的声音是什么样子。您必须使用这三个中的一个。

function callback(records) {
  records.forEach(function (record) {

在回调中事情变得有点棘手。回调接收一个MutationRecord数组每个MutationRecord可以描述一种类型的几个变化(childListattributes,或characterData)。由于我只告诉观察者注意childList,因此我不会费心检查类型。

var list = record.addedNodes;

在这里,我获取了所有添加的子节点的 NodeList。对于所有未添加节点的记录(并且可能有很多这样的记录),这将是空的。

从那时起,我遍历添加的节点并找到任何<select>元素。

这里没有什么真正复杂的。

jQuery

...但您要求使用 jQuery。美好的。

(function($) {

  var observers = [];

  $.event.special.domNodeInserted = {

    setup: function setup(data, namespaces) {
      var observer = new MutationObserver(checkObservers);

      observers.push([this, observer, []]);
    },

    teardown: function teardown(namespaces) {
      var obs = getObserverData(this);

      obs[1].disconnect();

      observers = $.grep(observers, function(item) {
        return item !== obs;
      });
    },

    remove: function remove(handleObj) {
      var obs = getObserverData(this);

      obs[2] = obs[2].filter(function(event) {
        return event[0] !== handleObj.selector && event[1] !== handleObj.handler;
      });
    },

    add: function add(handleObj) {
      var obs = getObserverData(this);

      var opts = $.extend({}, {
        childList: true,
        subtree: true
      }, handleObj.data);

      obs[1].observe(this, opts);

      obs[2].push([handleObj.selector, handleObj.handler]);
    }
  };

  function getObserverData(element) {
    var $el = $(element);

    return $.grep(observers, function(item) {
      return $el.is(item[0]);
    })[0];
  }

  function checkObservers(records, observer) {
    var obs = $.grep(observers, function(item) {
      return item[1] === observer;
    })[0];

    var triggers = obs[2];

    var changes = [];

    records.forEach(function(record) {
      if (record.type === 'attributes') {
        if (changes.indexOf(record.target) === -1) {
          changes.push(record.target);
        }

        return;
      }

      $(record.addedNodes).toArray().forEach(function(el) {
        if (changes.indexOf(el) === -1) {
          changes.push(el);
        }
      })
    });

    triggers.forEach(function checkTrigger(item) {
      changes.forEach(function(el) {
        var $el = $(el);

        if ($el.is(item[0])) {
          $el.trigger('domNodeInserted');
        }
      });
    });
  }

})(jQuery);

这将domNodeInserted使用jQuery 特殊事件 API创建一个名为 的新事件你可以像这样使用它:

$(document).on("domNodeInserted", "select", function () {
  $(this).combobox();
});

我个人建议寻找一个类,因为有些库会创建select用于测试目的的元素。

当然,您也可以.off("domNodeInserted", ...)通过传入这样的数据来使用或微调观看:

$(document.body).on("domNodeInserted", "select.test", {
  attributes: true,
  subtree: false
}, function () {
  $(this).combobox();
});

select.test每当直接在主体内部的元素的属性更改时,这将触发对元素外观的检查

你可以在下面或jsFiddle上看到它


笔记

这个 jQuery 代码是一个相当基本的实现。在其他地方的修改使您的选择器有效的情况下,它不会触发。

例如,假设您的选择器是.test select并且文档已经有一个<select>. 添加类testto<body>将使选择器有效,但因为我只检查record.targetand record.addedNodes,事件不会触发。更改必须发生在您希望自己选择的元素上。

这可以通过在发生突变时查询选择器来避免。我选择不这样做是为了避免对已经处理过的元素造成重复事件。正确处理相邻一般的兄弟组合会使事情变得更加棘手。

如需更全面的解决方案,请参阅https://github.com/pie6k/jquery.initialize,如Damien Ó Ceallaigh回答中所述但是,该库的作者宣布该库已经过时并建议您不要为此使用 jQuery。

惊人。谢谢你。
2021-04-04 07:44:39

您可以使用DOMNodeInserted突变事件(无需委托):

$('body').on('DOMNodeInserted', function(e) {
    var target = e.target; //inserted element;
});

编辑:突变事件弃用,使用突变观察者,而不是

刚刚想出了这个似乎解决了我所有 ajax 问题的解决方案。

对于准备好的事件,我现在使用这个:

function loaded(selector, callback){
    //trigger after page load.
    $(function () {
        callback($(selector));
    });
    //trigger after page update eg ajax event or jquery insert.
    $(document).on('DOMNodeInserted', selector, function () {
        callback($(this));
    });
}

loaded('.foo', function(el){
    //some action
    el.css('background', 'black');
});

对于正常的触发事件,我现在使用这个:

$(document).on('click', '.foo', function () {
    //some action
    $(this).css('background', 'pink');
});

有一个插件,adampietrasiak/jquery.initialize,它基于MutationObserver它简单地实现了这一点。

$.initialize(".some-element", function() {
    $(this).css("color", "blue");
});