当DOM发生变化时,如何重新运行JavaScript?

当DOM发生变化时,如何重新运行JavaScript?,javascript,meteor,Javascript,Meteor,我正在使用Template.rendered设置下拉列表替换,如下所示: Template.productEdit.rendered = function() { if( ! this.rendered) { $('.ui.dropdown').dropdown(); this.rendered = true; } }; 但是当DOM发生变异时,我如何重新运行它呢?助手会为选择选项返回新值,但我不知道在哪里重新执行.dropdown()假设您正在

我正在使用Template.rendered设置下拉列表替换,如下所示:

Template.productEdit.rendered = function() {
    if( ! this.rendered) {
        $('.ui.dropdown').dropdown();
        this.rendered = true;
    }
};

但是当DOM发生变异时,我如何重新运行它呢?助手会为选择选项返回新值,但我不知道在哪里重新执行.dropdown()

假设您正在使用插件,则可以定义四个回调:

onChange(值,文本,$choice):在选择下拉项后调用。接收所选内容和活动菜单元素的名称和值

onNoResults(searchValue):在搜索没有匹配值的下拉列表后调用

onShow:在显示下拉列表后调用

onHide:在隐藏下拉列表后调用

要使用它们,请为dropdown()函数指定一个参数:

$(".ui.dropdown").dropdown({
    onChange: function(value, text, $choice) {alert("You chose " + text + " with the value " + value);},
    onNoResults: function(searchValue) {alert("Your search for " + searchValue + " returned no results");}
    onShow: function() {alert("Dropdown shown");},
    onHide: function() {alert("Dropdown hidden");}
});

我建议您阅读您使用的所有插件的详细信息。

我认为您不希望在整个DOM呈现之前运行此插件,否则事件处理程序将在插入的每个元素上运行:

var rendered = false;
Template.productEdit.rendered = function() {rendered: true};
为了避免在已经是下拉列表的元素上重新运行此操作,您可以为新元素提供一个类,在将它们设置为下拉列表时将其删除

<div class="ui dropdown not-dropdownified"></div>

这将减少触发事件时执行的操作数量,并可以阻止调用堆栈耗尽

以下是我的初步答案,它可以工作,但我仍然希望Meteor有某种模板变异回调,而不是这种更麻烦的方法:

Template.productEdit.rendered = function() {
    if( ! this.rendered) {
        $('.ui.dropdown').dropdown();

        var mutationOptions = {
            childList: true,
            subtree: true
        }

        var mutationObserver = new MutationObserver(function(mutations, observer){
            observer.disconnect(); // otherwise subsequent DOM changes will recursively trigger this callback

            var selectChanged = false;

            mutations.map(function(mu) {
                var mutationTargetName = Object.prototype.toString.call(mu.target).match(/^\[object\s(.*)\]$/)[1];
                if(mutationTargetName === 'HTMLSelectElement') {
                    console.log('Select Changed');
                    selectChanged = true;
                }
            });

            if(selectChanged) {
                console.log('Re-init Select');
                $('.ui.dropdown').dropdown('restore defaults');
                $('.ui.dropdown').dropdown('refresh');
                $('.ui.dropdown').dropdown('setup select');
            }

            mutationObserver.observe(document, mutationOptions); // Start observing again
        });

        mutationObserver.observe(document, mutationOptions);

        this.rendered = true;
    }
};

这种方法使用了一些语法帮助,我找到了

这是哪个下拉插件?我猜它会发出某种事件,你可以将函数附加到其中。在这种情况下,这更像是一个一般的javascript/jquery问题,而不是流星问题。不,这绝对是流星问题。Meteor更改了DOM,所以我需要在DOM更改后立即触发下拉菜单重置。我需要一个从Meteor到Meteor的回调,在其中触发下拉插件重置。对不起,但这不是一个一般的JS问题。它是关于Meteor DOM更改和触发后续代码的,在本例中是一个下拉插件。上面的插件API方法还不够。例如,onChange()用于当用户选择一个新值时,但由于Meteor的反应性,我需要根据基础DOM的更改重置插件。我仍然发现这是一个一般的jQuery/javascript问题,可能是重复的,至少我让它在每次DOM更改时使用那里的答案运行一个函数。你可能会把它塞进流星事件处理程序中。在修改了一个模板后,我还在寻找一个合适的流星回调,但似乎没有?我将按照建议查看MutationEvent,它看起来是一个非常好的解决方案。谢谢你的建议。谢谢,不过对我来说,这使浏览器崩溃了超出了最大调用堆栈“”。我确实读过,观察MutationEvent可能是危险的,我将不得不找出一个解决办法。请参阅编辑中关于解决这个问题的可能方法的部分。另外,您是否可以在这个问题中添加javascript标记?我认为这可能会使代码的语法突出显示起作用。我正在尝试这里描述的更新的变异方法,因为DOMSubtreeModified显然已被弃用:
Template.productEdit.rendered = function() {
    if( ! this.rendered) {
        $('.ui.dropdown').dropdown();

        var mutationOptions = {
            childList: true,
            subtree: true
        }

        var mutationObserver = new MutationObserver(function(mutations, observer){
            observer.disconnect(); // otherwise subsequent DOM changes will recursively trigger this callback

            var selectChanged = false;

            mutations.map(function(mu) {
                var mutationTargetName = Object.prototype.toString.call(mu.target).match(/^\[object\s(.*)\]$/)[1];
                if(mutationTargetName === 'HTMLSelectElement') {
                    console.log('Select Changed');
                    selectChanged = true;
                }
            });

            if(selectChanged) {
                console.log('Re-init Select');
                $('.ui.dropdown').dropdown('restore defaults');
                $('.ui.dropdown').dropdown('refresh');
                $('.ui.dropdown').dropdown('setup select');
            }

            mutationObserver.observe(document, mutationOptions); // Start observing again
        });

        mutationObserver.observe(document, mutationOptions);

        this.rendered = true;
    }
};