我需要能够动态创建<select>
元素并将其转换为jQuery .combobox()
。这应该是元素创建事件,而不是某些“click”事件,在这种情况下我可以使用jQuery .on()
。
这样的事情存在吗?
$(document).on("create", "select", function() {
$(this).combobox();
}
我不愿意使用livequery,因为它已经过时了。
UPDATE 上面提到的select / combobox通过ajax加载到jQuery颜色框(模态窗口),因此问题 - 我只能使用colorbox onComplete
启动组合框,但是在更改时一个组合框必须动态创建另一个select / combobox,因此我需要一种更通用的方法来检测元素的创建(在这种情况下为select
)。
UPDATE2 为了尝试进一步解释这个问题 - 我递归地创建了select/combobox
个元素,.combobox()
中也有很多启动代码,因此如果我使用了经典的方法,就像@bipen's answer一样,我的代码会膨胀到疯狂的水平。希望这能更好地解释问题。
UPDATE3 谢谢大家,我现在明白,由于DOMNodeInserted
的弃用,DOM变异仍然存在空白,并且没有解决此问题的方法。我只需要重新考虑我的申请。
答案 0 :(得分:51)
您可以on
DOMNodeInserted
事件来获取代码将其添加到文档中的事件。
$('body').on('DOMNodeInserted', 'select', function () {
//$(this).combobox();
});
$('<select>').appendTo('body');
$('<select>').appendTo('body');
在这里摆弄:http://jsfiddle.net/Codesleuth/qLAB2/3/
编辑:阅读后我只需要仔细检查DOMNodeInserted
不会导致浏览器出现问题。来自2010年的This question表明IE不支持该事件,因此如果可以,请进行测试。
请看这里:[link] 警告! DOMNodeInserted事件类型在本规范中定义,以供参考和完整,但此规范deprecates使用此事件类型。
答案 1 :(得分:19)
您可以使用 DOMNodeInserted
突变事件(无需委托):
$('body').on('DOMNodeInserted',function(e){
var target = e.target; //inserted element;
});
编辑:Mutation events 已弃用,请改用<{3}}
答案 2 :(得分:6)
刚刚想出了解决我所有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');
});
答案 3 :(得分:4)
这可以通过DOM4 MutationObservers
完成,但只适用于Firefox 14 + / Chrome 18+(目前)。
然而,有一个“epic hack”(作者的话不是我的!)适用于支持CSS3动画的所有浏览器:IE10,Firefox 5 +,Chrome 3 +,Opera 12,Android 2.0 +, Safari 4+。请参阅博客中的demo。黑客是使用具有给定名称的CSS3动画事件,该事件在JavaScript中被观察和操作。
答案 4 :(得分:4)
似乎可靠的一种方式(虽然只在Firefox和Chrome中测试)是使用JavaScript来监听animationend
(或者它的camelCased,以及前缀,兄弟{{1}事件,并将短暂的(在演示0.01秒内)动画应用于您计划添加的元素类型。当然,这不是animationEnd
事件,而是近似(在兼容的浏览器中)onCreate
类型的事件;以下是概念验证:
onInsertion
使用以下HTML:
$(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
});
并且(缩写为prefixed-versions-removed虽然存在于下面的Fiddle中)CSS:
<div class="wrapper">
<button class="add">add a div element</button>
</div>
显然可以调整CSS以适应相关元素的位置,以及jQuery中使用的选择器(它应该尽可能地接近插入点)。
事件名称的文档:
/* 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;
}
参考文献:
答案 5 :(得分:4)
正如其他几个答案所述,mutation events已被弃用,因此您应该使用MutationObserver代替。由于没有人提供任何细节,这里就是......
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 });
这使观察者启动。第一个参数是观察者将观察更改的节点。第二个参数是options for what to watch for。 childList
表示我想要监视要添加或删除的子元素。 subtree
是一个修饰符,扩展childList
以监视此元素子树中任何位置的更改(否则,它只会直接查看<body>
内的更改)。另外两个重要的可能性是attributes
和characterData
,这意味着它们的含义。
function callback(records) {
records.forEach(function (record) {
在回调中,事情变得有点棘手。回调接收MutationRecord个数组。每个MutationRecord都可以描述一种类型的多个更改(childList
,attributes
或characterData
)。由于我只是告诉观察者注意childList
,我不打算检查类型。
var list = record.addedNodes;
就在这里,我抓住了添加的所有子节点的NodeList。对于未添加节点的所有记录,这将是空的(并且可能有许多此类记录)。
从那时起,我遍历添加的节点并找到任何<select>
元素。
这里真的很复杂。
...但你问了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);
这会使用jQuery special events API创建一个名为domNodeInserted
的新事件。您可以像这样使用它:
$(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
元素的外观。
(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>
这个jQuery代码是一个相当基本的实现。如果其他地方的修改使您的选择器有效,则不会触发它。
例如,假设您的选择器为.test select
且文档已有<select>
。将班级test
添加到<body>
会使选择器生效,但由于我只检查record.target
和record.addedNodes
,因此该事件不会触发。更改必须发生在您希望自己选择的元素上。
这可以通过在发生突变时查询选择器来避免。我选择不这样做以避免为已经处理过的元素造成重复事件。正确处理general sibling combinators或https://github.com/pie6k/jquery.initialize会使事情变得更加棘手。
要获得更全面的解决方案,请参阅Damien Ó Ceallaigh answer中提及的information here。
答案 6 :(得分:3)
对我来说绑定身体是行不通的。使用jQuery.bind()绑定到文档。
$(document).bind('DOMNodeInserted',function(e){
var target = e.target;
});
答案 7 :(得分:3)
有一个插件adampietrasiak/jquery.initialize,它基于 MutationObserver
,实现了这一目标。
$.initialize(".some-element", function() {
$(this).css("color", "blue");
});
答案 8 :(得分:1)
我认为值得一提的是,在某些情况下,这会起作用:
$( document ).ajaxComplete(function() {
// Do Stuff
});
答案 9 :(得分:1)
而不是...
$(".class").click( function() {
// do something
});
你可以写...
$('body').on('click', '.class', function() {
// do something
});
答案 10 :(得分:0)
创建一个带有ID的<select>
,将其附加到文档..并调用.combobox
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();
这应该可以解决问题..你可以隐藏选择,如果你想要,并在.combobox
显示它之后......或者使用find ..
$(document).find('select').combobox() //though this is not good performancewise
答案 11 :(得分:-1)
如果您使用angularjs,您可以编写自己的指令。我和bootstrapSwitch有同样的问题。我得打电话
$("[name='my-checkbox']").bootstrapSwitch();
在javascript但我的html输入对象当时没有创建。所以我编写了一个自己的指令并创建了输入元素
<input type="checkbox" checkbox-switch>
在指令中我编译元素以通过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();
}
}
});