简体   繁体   English

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

[英]What is the best way to deal with elements/objects that listen AND trigger events?

I have asked some way similar question yesterday, but after one day of research I've found it too complicated and not precise enough, so I deleted it. 昨天我问过类似的问题,但是经过一天的研究,我发现它过于复杂且不够精确,因此我删除了它。

So I have created another fiddle here , which should be self-descriptive in most parts. 因此,我在这里创建了另一个小提琴,该小提琴在大多数情况下应该是自我描述的。

Below, you can find a HTML and JavaScript part of it: 在下面,您可以找到其中的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>

And the promised Javascript goes here: 承诺的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) {
    // ...
});

The thing is, that I do not know what is the best approach to situations like this, when elements are both: listeners to the events AND have ability to TRIGGER the same events. 事实是,当元素同时是:事件的侦听器和触发相同事件的能力时,我不知道对这种情况最好的方法是什么。 So, for example selecting an option from a native SELECT element causes event to trigger and select appropriate LI element on the other list. 因此,例如,从本地SELECT元素中选择一个选项会导致事件触发,并在其他列表上选择适当的LI元素。 But as the event has to deal also with vice-versa situation, it also tries to update the SELECT again, which is useless and - what's even worse - causes an infinite resursion (hopefully stopped by smart browsers). 但是,由于该事件还必须处理相反的情况,因此它还会尝试再次更新SELECT ,这是无用的,更糟糕​​的是,这会导致无限递归(希望被智能浏览器停止)。

Try to uncomment #46 line of JavaScript code in my fiddle to see what I am talking about. 尝试在我的小提琴中取消注释JavaScript代码的#46行,以了解我在说什么。

So what I'm looking for is a nice way of detecting where the event came from, and then excluding it's source from the list of possible callbacks. 因此,我正在寻找一种检测事件从何处来,然后将其来源从可能的回调列表中排除的好方法。

OR - maybe I'm trying to solve the problem in using wrong approach? 或者-也许我正在尝试使用错误的方法来解决问题? Maybe I have read not enough for two days I've already spend on this? 也许我已经花了两天没有读足够的东西? ;) ;)

Please help me if you can. 如果可以,请你帮助我。

I would separate UI generated events from the ones triggered from code. 我将UI生成的事件与代码触发的事件分开。 Also, there is no need for custom events and 2 change handlers on SELECT . 另外,不需要自定义事件和SELECT上的2个change处理程序。 Also, there is no need to re-trigger change event from your custom event. 此外,也无需从您的自定义事件中重新触发change事件。

My suggestion for your problem is something like: 我对您的问题的建议是:

$('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
    // ...
}

In short: keep your UI event handlers short (identify context, ie data related to the event). 简而言之:保持UI事件处理程序简短(标识上下文,即与事件相关的数据)。 The handler should then make a call to utility method (if appropriate via custom event) updating the view (if necessary) and processing the data. 然后,处理程序应调用实用程序方法(如果需要,通过自定义事件),以更新视图(如果需要)并处理数据。

If further events are required, do not (re)trigger the same ones as this is now new situation, the program state changed and different event (eg after_x ) is more appropriate. 如果需要更多事件,则不要(重新)触发与现在新的情况相同的事件,程序状态已更改,并且不同的事件(例如after_x )更合适。

If pretty select plugin bothers you, as part of updating the view do either: 如果漂亮的精选插件困扰您,请在更新视图时执行以下任一操作:

  1. call: update method of prettyselect plugin: $('select[name=country]').prettyselect('update') 调用:prettyselect插件的update方法: $('select[name=country]').prettyselect('update')
  2. trigger change.ps event on select : $('select[name=country]').trigger('change.ps') select上触发change.ps事件: $('select[name=country]').trigger('change.ps')

Take a look at the source and see how it all works. 看一下源代码 ,看看它们如何工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM