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

时间:2022-10-22 07:35:08

I need to be able to dynamically create <select> element and turn it into jQuery .combobox(). This should be element creation event, as opposed to some "click" event in which case I could just use jQuery .on().

我需要能够动态创建

So does something like this exist?

这样的东西存在吗?

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

I'm reluctant to use livequery, because it's very outdated.

我不愿意使用livequery,因为它非常过时。

UPDATE The mentioned select/combobox is loaded via ajax into a jQuery colorbox (modal window), thus the problem - I can only initiate combobox using colorbox onComplete, however on change of one combobox another select/combobox must be dynamically created, therefor I need a more generic way to detect creation of an element (selectin this case).

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

UPDATE2 To try and explain the problem further - I have select/combobox elements created recursively, there is also a lot of initiating code inside .combobox(), therefore if I used a classic approach, like in @bipen's answer, my code would inflate to insane levels. Hope this explains the problem better.

UPDATE2尝试进一步解释这个问题——我递归地创建了select/combobox元素,在.combobox()中也有很多初始化代码,因此如果我使用一种经典的方法,比如@bipen的答案,我的代码就会膨胀到疯狂的程度。希望这能更好地解释这个问题。

UPDATE3 Thanks everyone, I now understand that since deprecation of DOMNodeInserted there is a void left in DOM mutation and there is no solution to this problem. I'll just have to rethink my application.

UPDATE3谢谢大家,我现在了解到,由于domnodeinsert遭到弃用,所以DOM突变中还剩下一个空,因此没有办法解决这个问题。我得重新考虑我的申请。

10 个解决方案

#1


41  

You can on the DOMNodeInserted event to get an event for when it's added to the document by your code.

您可以在domnodeplugged事件上获取事件,当它被您的代码添加到文档时。

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

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

Fiddled here: http://jsfiddle.net/Codesleuth/qLAB2/3/

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

EDIT: after reading around I just need to double check DOMNodeInserted won't cause problems across browsers. This question from 2010 suggests IE doesn't support the event, so test it if you can.

编辑:在阅读完四周后,我只需要再次检查domnodeinsert不会在浏览器之间造成问题。这个来自2010年的问题表明IE不支持这个事件,所以如果可以的话测试一下。

See here: [link] Warning! the DOMNodeInserted event type is defined in this specification for reference and completeness, but this specification deprecates the use of this event type.

在这里看到的:[链接]警告!在本规范中定义了domnodeinsert事件类型以作为参考和完整性,但是本规范不赞成使用此事件类型。

#2


14  

You can use DOMNodeInserted mutation event (no need delegation) :

可以使用domnodeinsert突变事件(不需要委托):

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

EDIT: Mutation events are deprecated, use mutation observer instead

编辑:不赞成使用突变事件,使用突变观察者代替

#3


5  

Just came up with this solution that seems to solve all my ajax problems.

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

For on ready events I now use this:

对于准备好的事件,我现在使用以下方法:

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');
});

And for normal trigger events I now use this:

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

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

#4


4  

This could be done with DOM4 MutationObservers but will only work in Firefox 14+/Chrome 18+ (for now).

这可以通过DOM4 mutation观察者来完成,但是只会在Firefox 14+/Chrome 18+(现在)中使用。

However there is an "epic hack" (author's words not mine!) that works in all browsers that support CSS3 animations which are: IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+. See the demo from the blog. The hack is to use a CSS3 animation event with a given name that is observed and acted upon in JavaScript.

然而,有一种“史诗黑客”(作者的话不是我的!)可以在所有支持CSS3动画的浏览器中使用:IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+。请参见博客中的演示。这个技巧是使用一个CSS3动画事件,它的名字在JavaScript中被观察和执行。

#5


4  

One way, which seems reliable (though tested only in Firefox and Chrome) is to use JavaScript to listen for the animationend (or its camelCased, and prefixed, sibling animationEnd) event, and apply a short-lived (in the demo 0.01 second) animation to the element-type you plan to add. This, of course, is not an onCreate event, but approximates (in compliant browsers) an onInsertion type of event; the following is a proof-of-concept:

方法之一,这似乎是可靠的(尽管测试只有在Firefox和Chrome)是使用JavaScript来侦听animationend(或其camelCased前缀,兄弟姐妹animationend)事件,并应用一个短命的演示(0.01秒)动画元素类型你添加的计划。这一点,当然,不是一个onCreate事件,但接近(在兼容的浏览器)onInsertion类型的事件;以下是概念证明:

$(document).on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function(e){
    var eTarget = e.target;
    console.log(eTarget.tagName.toLowerCase() + ' added to ' + eTarget.parentNode.tagName.toLowerCase());
    $(eTarget).draggable(); // or whatever other method you'd prefer
});

With the following HTML:

以下HTML:

<div class="wrapper">
    <button class="add">add a div element</button>
</div>

And (abbreviated, prefixed-versions-removed though present in the Fiddle, below) CSS:

并且(缩写,前缀固定版本,虽然现在在小提琴中被删除)CSS:

/* vendor-prefixed alternatives removed for brevity */
@keyframes added {
    0% {
        color: #fff;
    }
}

div {
    color: #000;
    /* vendor-prefixed properties removed for brevity */
    animation: added 0.01s linear;
    animation-iteration-count: 1;
}

JS Fiddle demo.

JS小提琴演示。

Obviously the CSS can be adjusted to suit the placement of the relevant elements, as well as the selector used in the jQuery (it should really be as close to the point of insertion as possible).

显然,可以调整CSS以适应相关元素的位置,以及jQuery中使用的选择器(它应该尽可能接近插入点)。

Documentation of the event-names:

事件名称的文档:

Mozilla   |  animationend
Microsoft |  MSAnimationEnd
Opera     |  oanimationend
Webkit    |  webkitAnimationEnd
W3C       |  animationend

References:

引用:

#6


2  

For me binding to the body does not work. Binding to the document using jQuery.bind() does.

对我来说,对身体的束缚不起作用。绑定到使用jQuery.bind()的文档。

$(document).bind('DOMNodeInserted',function(e){
             var target = e.target;
         });

#7


2  

There is a plugin, adampietrasiak/jquery.initialize, which is based on MutationObserver that achieves this simply.

有一个插件,adampietrasiak/jquery。初始化,它基于简单实现这一点的MutationObserver。

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

#8


1  

As mentioned in several other answers, mutation events have been deprecated, so you should use MutationObserver instead. Since nobody has given any details on that yet, here it goes...

正如在其他几个答案中提到的,突变事件已经被弃用,因此应该使用MutationObserver。既然还没有人给出任何细节,那么……

Basic JavaScript API

The API for MutationObserver is fairly simple. It's not quite as simple as the mutation events, but it's still okay.

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>

Let's break that down.

让我们打破它。

var observer = new MutationObserver(callback);

This creates the observer. The observer isn't watching anything yet; this is just where the event listener gets attached.

这将创建观察者。观察者还没有看到任何东西;这就是事件监听器连接的地方。

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

This makes the observer start up. The first argument is the node that the observer will watch for changes on. The second argument is the options for what to watch for. The childList means I want to watch for child elements being added or removed. The subtree is a modifier extends childList to watch for changes anywhere in this element's subtree (otherwise, it would just look at changes directly within <body>). Two other important possibilities are attributes and characterData, which mean about what they sound like.

这让观察者开始了。第一个参数是观察者将监视的节点。第二个论点是要注意的选项。子列表意味着我希望查看添加或删除的子元素。子树是一个扩展子列表的修饰符,用于监视元素子树中任何地方的更改(否则,它只会直接查看)中的更改。另外两个重要的可能性是属性和字符数据,这意味着它们听起来像什么。

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

Things get a little tricky inside the callback. The callback receives an array of MutationRecords. Each MutationRecord can describe several changes of one type (childList, attributes, or characterData). Since I only told the observer to watch for childList, I won't bother checking the type.

在回调中,事情变得有点棘手。回调接收一个MutationRecords数组。每个MutationRecord可以描述一种类型(子列表、属性或字符数据)的多个更改。因为我只告诉《观察者》要看孩子名单,所以我不会去检查类型。

var list = record.addedNodes;

Right here I grab a NodeList of all the child nodes that were added. This will be empty for all the records where nodes aren't added (and there may be many such records).

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

From there on, I loop through the added nodes and find any that are <select> elements.

从这里开始,我循环遍历添加的节点并找到任何

Nothing really complex here.

这里没有复杂的。

jQuery

...but you asked for jQuery. Fine.

…但是你要的是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);

This creates a new event called domNodeInserted, using the jQuery special events API. You can use it like so:

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

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

I would personally suggest looking for a class because some libraries will create select elements for testing purposes.

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

Naturally, you can also use .off("domNodeInserted", ...) or fine-tune the watching by passing in data like this:

当然,您也可以使用.off(“domnodeplugged”,…)或通过传递这样的数据对监视进行微调:

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

This would trigger checking for the appearance of a select.test element whenever attributes changed for elements directly inside the body.

这将触发检查select的外观。当在主体内部的元素的属性发生变化时,测试元素。

You can see it live below or on jsFiddle.

你可以看到它在jsFiddle或者是在jsFiddle。

(function($) {
  $(document).on("domNodeInserted", "select", function() {
    console.log(this);
    //$(this).combobox();
  });
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script>
  // For testing
  setTimeout(function() {
    var $el = document.createElement('select');
    document.body.appendChild($el);
  }, 500);
</script>

<script>
  (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);
</script>


Note

This jQuery code is a fairly basic implementation. It does not trigger in cases where modifications elsewhere make your selector valid.

这个jQuery代码是一个非常基本的实现。当其他地方的修改使选择器有效时,它不会触发。

For example, suppose your selector is .test select and the document already has a <select>. Adding the class test to <body> will make the selector valid, but because I only check record.target and record.addedNodes, the event would not fire. The change has to happen to the element you wish to select itself.

例如,假设您的选择器是.test select,并且文档已经有一个

This could be avoided by querying for the selector whenever mutations happen. I chose not to do that to avoid causing duplicate events for elements that had already been handled. Properly dealing with adjacent or general sibling combinators would make things even trickier.

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

For a more comprehensive solution, see https://github.com/pie6k/jquery.initialize, as mentioned in Damien Ó Ceallaigh's answer.

要获得更全面的解决方案,请参阅https://github.com/pie6k/jquery.initialize,正如Damien O Ceallaigh的答案中提到的。

#9


0  

create a <select> with id , append it to document.. and call .combobox

创建一个带有id的

  var dynamicScript='<select id="selectid"><option value="1">...</option>.....</select>'
  $('body').append(dynamicScript); //append this to the place your wanted.
  $('#selectid').combobox();  //get the id and add .combobox();

this should do the trick.. you can hide the select if you want and after .combobox show it..or else use find..

这应该能奏效。你可以隐藏选择,如果你想,然后在combobox显示它。否则使用find . .

 $(document).find('select').combobox() //though this is not good performancewise

#10


-1  

if you are using angularjs you can write your own directive. I had the same problem whith bootstrapSwitch. I have to call $("[name='my-checkbox']").bootstrapSwitch(); in javascript but my html input object was not created at that time. So I write an own directive and create the input element with <input type="checkbox" checkbox-switch>

如果您正在使用angularjs,您可以编写自己的指令。我在bootstrapSwitch遇到了同样的问题。我必须调用$(“[name='my-checkbox']).bootstrapSwitch();在javascript中,但是我的html输入对象当时没有创建。因此,我编写了一个自己的指令,并使用

In the directive I compile the element to get access via javascript an execute the jquery command (like your .combobox() command). Very important is to remove the attribute. Otherwise this directive will call itself and you have build a loop

在该指令中,我编译了该元素以通过javascript访问jquery命令(如您的.combobox()命令)。非常重要的是删除属性。否则这个指令会调用自己,你就建立了一个循环

app.directive("checkboxSwitch", function($compile) {
return {
    link: function($scope, element) {
        var input = element[0];
        input.removeAttribute("checkbox-switch");
        var inputCompiled = $compile(input)($scope.$parent);
        inputCompiled.bootstrapSwitch();
    }
}
});

#1


41  

You can on the DOMNodeInserted event to get an event for when it's added to the document by your code.

您可以在domnodeplugged事件上获取事件,当它被您的代码添加到文档时。

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

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

Fiddled here: http://jsfiddle.net/Codesleuth/qLAB2/3/

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

EDIT: after reading around I just need to double check DOMNodeInserted won't cause problems across browsers. This question from 2010 suggests IE doesn't support the event, so test it if you can.

编辑:在阅读完四周后,我只需要再次检查domnodeinsert不会在浏览器之间造成问题。这个来自2010年的问题表明IE不支持这个事件,所以如果可以的话测试一下。

See here: [link] Warning! the DOMNodeInserted event type is defined in this specification for reference and completeness, but this specification deprecates the use of this event type.

在这里看到的:[链接]警告!在本规范中定义了domnodeinsert事件类型以作为参考和完整性,但是本规范不赞成使用此事件类型。

#2


14  

You can use DOMNodeInserted mutation event (no need delegation) :

可以使用domnodeinsert突变事件(不需要委托):

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

EDIT: Mutation events are deprecated, use mutation observer instead

编辑:不赞成使用突变事件,使用突变观察者代替

#3


5  

Just came up with this solution that seems to solve all my ajax problems.

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

For on ready events I now use this:

对于准备好的事件,我现在使用以下方法:

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');
});

And for normal trigger events I now use this:

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

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

#4


4  

This could be done with DOM4 MutationObservers but will only work in Firefox 14+/Chrome 18+ (for now).

这可以通过DOM4 mutation观察者来完成,但是只会在Firefox 14+/Chrome 18+(现在)中使用。

However there is an "epic hack" (author's words not mine!) that works in all browsers that support CSS3 animations which are: IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+. See the demo from the blog. The hack is to use a CSS3 animation event with a given name that is observed and acted upon in JavaScript.

然而,有一种“史诗黑客”(作者的话不是我的!)可以在所有支持CSS3动画的浏览器中使用:IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+。请参见博客中的演示。这个技巧是使用一个CSS3动画事件,它的名字在JavaScript中被观察和执行。

#5


4  

One way, which seems reliable (though tested only in Firefox and Chrome) is to use JavaScript to listen for the animationend (or its camelCased, and prefixed, sibling animationEnd) event, and apply a short-lived (in the demo 0.01 second) animation to the element-type you plan to add. This, of course, is not an onCreate event, but approximates (in compliant browsers) an onInsertion type of event; the following is a proof-of-concept:

方法之一,这似乎是可靠的(尽管测试只有在Firefox和Chrome)是使用JavaScript来侦听animationend(或其camelCased前缀,兄弟姐妹animationend)事件,并应用一个短命的演示(0.01秒)动画元素类型你添加的计划。这一点,当然,不是一个onCreate事件,但接近(在兼容的浏览器)onInsertion类型的事件;以下是概念证明:

$(document).on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function(e){
    var eTarget = e.target;
    console.log(eTarget.tagName.toLowerCase() + ' added to ' + eTarget.parentNode.tagName.toLowerCase());
    $(eTarget).draggable(); // or whatever other method you'd prefer
});

With the following HTML:

以下HTML:

<div class="wrapper">
    <button class="add">add a div element</button>
</div>

And (abbreviated, prefixed-versions-removed though present in the Fiddle, below) CSS:

并且(缩写,前缀固定版本,虽然现在在小提琴中被删除)CSS:

/* vendor-prefixed alternatives removed for brevity */
@keyframes added {
    0% {
        color: #fff;
    }
}

div {
    color: #000;
    /* vendor-prefixed properties removed for brevity */
    animation: added 0.01s linear;
    animation-iteration-count: 1;
}

JS Fiddle demo.

JS小提琴演示。

Obviously the CSS can be adjusted to suit the placement of the relevant elements, as well as the selector used in the jQuery (it should really be as close to the point of insertion as possible).

显然,可以调整CSS以适应相关元素的位置,以及jQuery中使用的选择器(它应该尽可能接近插入点)。

Documentation of the event-names:

事件名称的文档:

Mozilla   |  animationend
Microsoft |  MSAnimationEnd
Opera     |  oanimationend
Webkit    |  webkitAnimationEnd
W3C       |  animationend

References:

引用:

#6


2  

For me binding to the body does not work. Binding to the document using jQuery.bind() does.

对我来说,对身体的束缚不起作用。绑定到使用jQuery.bind()的文档。

$(document).bind('DOMNodeInserted',function(e){
             var target = e.target;
         });

#7


2  

There is a plugin, adampietrasiak/jquery.initialize, which is based on MutationObserver that achieves this simply.

有一个插件,adampietrasiak/jquery。初始化,它基于简单实现这一点的MutationObserver。

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

#8


1  

As mentioned in several other answers, mutation events have been deprecated, so you should use MutationObserver instead. Since nobody has given any details on that yet, here it goes...

正如在其他几个答案中提到的,突变事件已经被弃用,因此应该使用MutationObserver。既然还没有人给出任何细节,那么……

Basic JavaScript API

The API for MutationObserver is fairly simple. It's not quite as simple as the mutation events, but it's still okay.

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>

Let's break that down.

让我们打破它。

var observer = new MutationObserver(callback);

This creates the observer. The observer isn't watching anything yet; this is just where the event listener gets attached.

这将创建观察者。观察者还没有看到任何东西;这就是事件监听器连接的地方。

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

This makes the observer start up. The first argument is the node that the observer will watch for changes on. The second argument is the options for what to watch for. The childList means I want to watch for child elements being added or removed. The subtree is a modifier extends childList to watch for changes anywhere in this element's subtree (otherwise, it would just look at changes directly within <body>). Two other important possibilities are attributes and characterData, which mean about what they sound like.

这让观察者开始了。第一个参数是观察者将监视的节点。第二个论点是要注意的选项。子列表意味着我希望查看添加或删除的子元素。子树是一个扩展子列表的修饰符,用于监视元素子树中任何地方的更改(否则,它只会直接查看)中的更改。另外两个重要的可能性是属性和字符数据,这意味着它们听起来像什么。

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

Things get a little tricky inside the callback. The callback receives an array of MutationRecords. Each MutationRecord can describe several changes of one type (childList, attributes, or characterData). Since I only told the observer to watch for childList, I won't bother checking the type.

在回调中,事情变得有点棘手。回调接收一个MutationRecords数组。每个MutationRecord可以描述一种类型(子列表、属性或字符数据)的多个更改。因为我只告诉《观察者》要看孩子名单,所以我不会去检查类型。

var list = record.addedNodes;

Right here I grab a NodeList of all the child nodes that were added. This will be empty for all the records where nodes aren't added (and there may be many such records).

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

From there on, I loop through the added nodes and find any that are <select> elements.

从这里开始,我循环遍历添加的节点并找到任何

Nothing really complex here.

这里没有复杂的。

jQuery

...but you asked for jQuery. Fine.

…但是你要的是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);

This creates a new event called domNodeInserted, using the jQuery special events API. You can use it like so:

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

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

I would personally suggest looking for a class because some libraries will create select elements for testing purposes.

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

Naturally, you can also use .off("domNodeInserted", ...) or fine-tune the watching by passing in data like this:

当然,您也可以使用.off(“domnodeplugged”,…)或通过传递这样的数据对监视进行微调:

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

This would trigger checking for the appearance of a select.test element whenever attributes changed for elements directly inside the body.

这将触发检查select的外观。当在主体内部的元素的属性发生变化时,测试元素。

You can see it live below or on jsFiddle.

你可以看到它在jsFiddle或者是在jsFiddle。

(function($) {
  $(document).on("domNodeInserted", "select", function() {
    console.log(this);
    //$(this).combobox();
  });
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script>
  // For testing
  setTimeout(function() {
    var $el = document.createElement('select');
    document.body.appendChild($el);
  }, 500);
</script>

<script>
  (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);
</script>


Note

This jQuery code is a fairly basic implementation. It does not trigger in cases where modifications elsewhere make your selector valid.

这个jQuery代码是一个非常基本的实现。当其他地方的修改使选择器有效时,它不会触发。

For example, suppose your selector is .test select and the document already has a <select>. Adding the class test to <body> will make the selector valid, but because I only check record.target and record.addedNodes, the event would not fire. The change has to happen to the element you wish to select itself.

例如,假设您的选择器是.test select,并且文档已经有一个

This could be avoided by querying for the selector whenever mutations happen. I chose not to do that to avoid causing duplicate events for elements that had already been handled. Properly dealing with adjacent or general sibling combinators would make things even trickier.

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

For a more comprehensive solution, see https://github.com/pie6k/jquery.initialize, as mentioned in Damien Ó Ceallaigh's answer.

要获得更全面的解决方案,请参阅https://github.com/pie6k/jquery.initialize,正如Damien O Ceallaigh的答案中提到的。

#9


0  

create a <select> with id , append it to document.. and call .combobox

创建一个带有id的

  var dynamicScript='<select id="selectid"><option value="1">...</option>.....</select>'
  $('body').append(dynamicScript); //append this to the place your wanted.
  $('#selectid').combobox();  //get the id and add .combobox();

this should do the trick.. you can hide the select if you want and after .combobox show it..or else use find..

这应该能奏效。你可以隐藏选择,如果你想,然后在combobox显示它。否则使用find . .

 $(document).find('select').combobox() //though this is not good performancewise

#10


-1  

if you are using angularjs you can write your own directive. I had the same problem whith bootstrapSwitch. I have to call $("[name='my-checkbox']").bootstrapSwitch(); in javascript but my html input object was not created at that time. So I write an own directive and create the input element with <input type="checkbox" checkbox-switch>

如果您正在使用angularjs,您可以编写自己的指令。我在bootstrapSwitch遇到了同样的问题。我必须调用$(“[name='my-checkbox']).bootstrapSwitch();在javascript中,但是我的html输入对象当时没有创建。因此,我编写了一个自己的指令,并使用

In the directive I compile the element to get access via javascript an execute the jquery command (like your .combobox() command). Very important is to remove the attribute. Otherwise this directive will call itself and you have build a loop

在该指令中,我编译了该元素以通过javascript访问jquery命令(如您的.combobox()命令)。非常重要的是删除属性。否则这个指令会调用自己,你就建立了一个循环

app.directive("checkboxSwitch", function($compile) {
return {
    link: function($scope, element) {
        var input = element[0];
        input.removeAttribute("checkbox-switch");
        var inputCompiled = $compile(input)($scope.$parent);
        inputCompiled.bootstrapSwitch();
    }
}
});