处理侦听和触发事件的元素/对象的最佳方法是什么?

时间:2014-01-29 15:03:58

标签: javascript jquery javascript-events

昨天我问了一些类似的问题,但经过一天的研究,我发现它太复杂,不够精确,所以我把它删了。

所以我创建了另一个小提琴here,它在大多数部分应该是自我描述的。

下面,您可以找到HTML和JavaScript的一部分:

<select name="country">
    <option value="spain">Spain</option>
    <option value="sweden">Sweden</option>
    <option value="russia">Russia</option>
    <option value="canada">Canada</option>
</select>

<ul class="another-selector">
    <li data-value="spain">Spain</li>
    <li data-value="sweden">Sweden</li>
    <li data-value="russia">Russia</li>
    <li data-value="canada">Canda</li>
</ul>

承诺的Javascript就在这里:

// Following function is called when 'country_changed' event is triggered
var country_changed = function(event, data) {
    $another_selector_items = $('.another-selector')
        .children();

    $another_selector_items
        .removeClass('selected');

    $another_selector_items.each(function(index, element) {
        var $element = $(element);
        if ($element.data('value') == data.country)
            $element.addClass('selected');
    });

    var $select = $('select[name=country]');
    $select
        .children()
        .removeAttr('selected')
        .prop('selected', false)
        .filter('[value=' + data.country + ']')
        .attr('selected', 'selected')
        .prop('selected', true);

    // ----------------------------------------
    // Uncomment this to get infinite recursion:
    // ----------------------------------------
    //$select.trigger('change');
};

// Register event bound to the document
// (so not attached to any particular element)
$(document)
    .on("country_changed", country_changed);


// Bind changing the
$('select[name=country]').on('change', function(event) {
    $.event.trigger('country_changed', {
        country: $(this).val()
    });
});

// Bind clicking on the LI to triggering the event 
$('.another-selector').on('click', 'li', function(event) {
    $.event.trigger('country_changed', {
        country: $(this).data('value')
    });
});

// Separate 'change' event binding --- required for 'pretty select' plugin
$('select[name=country]').on('change', function(event, data) {
    // ...
});

问题是,我不知道这种情况的最佳方法是什么,当元素都是:事件的监听者和能够触发相同的事件。 因此,例如,从本机SELECT元素中选择一个选项会导致事件触发并在另一个列表中选择适当的LI元素。但是由于事件还必须处理反之亦然的情况,它还会尝试再次更新SELECT,这是无用的,甚至更糟糕的是 - 导致无限的恢复(希望智能浏览器停止)。

尝试在my fiddle中取消注释#46 一行JavaScript代码,看看我在说什么。

所以我正在寻找的是检测事件来源的好方法,然后从可能的回调列表中排除它的来源。

或者 - 也许我正试图用错误的方法解决问题?也许我已经阅读了不够两天我已经花在这上面了? ;)

如果可以,请帮助我。

1 个答案:

答案 0 :(得分:1)

我会将UI生成的事件与代码触发的事件分开。此外,change上不需要自定义事件和2 SELECT个处理程序。此外,您无需从自定义事件中重新触发change事件。

我对你的问题的建议是这样的:

$('select[name=country]').on('change', function(event) {
    var country = ... /* obtain country */

    selectContry(country);
});

$('.another-selector').on('click', 'li', function(event) {
    var country = ... /* obtain country */

    selectContry(country);
});

function selectContry(country) {
    // update view, e.g. SELECT and UL
    // ...

    // process new selection
    // ...
}

简而言之:保持UI事件处理程序的简短(识别上下文,即与事件相关的数据)。然后,处理程序应该调用实用程序方法(如果适当,通过自定义事件)更新视图(如果需要)并处理数据。

如果需要进一步的事件,请不要(重新)触发相同的事件,因为这是现在的新情况,程序状态发生了变化,不同的事件(例如after_x)更合适。

如果漂亮选择插件困扰您,作为更新视图的一部分,请执行以下操作:

  1. 调用:update prettyselect插件的方法:$('select[name=country]').prettyselect('update')
  2. 触发change.ps上的select事件:$('select[name=country]').trigger('change.ps')
  3. 看看source,看看它是如何运作的。