【问题标题】:How to run a function once when binding to multiple events that all trigger in Javascript?绑定到全部在Javascript中触发的多个事件时如何运行一次函数?
【发布时间】:2012-12-03 17:14:42
【问题描述】:

我有一个搜索输入,它侦听 keyupchange 以通过 Ajax 触发列表视图的更新。

看起来像这样:

input.on('keyup change', function(e) {
    if (timer) {
        window.clearTimeout(timer);
    }
    timer = window.setTimeout( function() {
        timer = null;
        val = input.val();
        el = input.closest('ul');
        // run a function - triggers Ajax
        widget[func](dyn, el, lib_template, locale, val, "update");
    }, interval );
});

一切正常,除了超时和绑定的处理,这会导致放置双 Ajax 请求而不是单个 Ajax 请求(当 keyup 已通过时,change 事件再次触发相同的 Ajax 请求) .

我可以通过添加另一个超时来“解决”这个问题:

var runner = false;

input.on('keyup change', function(e) {
    if ( runner === false ){
        runner = true;
        if (timer) {
            window.clearTimeout(timer);
        }
        timer = window.setTimeout( function() {
            timer = null;
            val = input.val();
            el = input.closest('ul');
            widget[func](dyn, el, lib_template, locale, val, "update");
            // ssh....
            window.setTimeout( function(){ runner = false; },2500);
        }, interval );
    }
});

但这一点都不好……

问题:
如何确保两个都触发的绑定,我需要的函数只运行一次?

编辑
Ajax 调用在这里触发:

widget[func](dyn, el, lib_template, locale, val, "update");

调用该函数构建动态列表视图

buildListView : function( dyn,el,lib_template,locale,val,what ){
    ...
    // this calls my AJax Config "getUsers"
    $.parseJSON( dynoData[ dyn.method ](cbk, val, dyn.display) );

 });

 // config AJAX
 getUsers: function(cbk, val, recs){
  var form = "",
  pullRetailers = ( val === undefined ? "" : val ),
  service = "../services/some.cfc",
  method = "by",
  returnformat = "json",
  targetUrl = "",
  formdata = "...manually_serialized...,
  successHandler = function(objResponse, cbk) {
     cbk( objResponse );
  };
  // finally pass to the generic JSON handler
  ajaxFormSubmit( form, service, formdata, targetUrl, successHandler, "yes", "", returnformat, cbk );
}

// generic AJAX
var ajaxFormSubmit = 
    function ( form, service, formdata, targetUrl, successHandler, dataHandler, errorHandler, returnformat, type ){
    ...

    $.ajax({
        async: false,
        type: type == "" ? "get" : type,
        url: service,
        data: formdata,
        contentType: 'application/x-www-form-urlencoded',
        dataType: returnformat,
        success: function( objResponse ){
            if (objResponse.SUCCESS == true || typeof objResponse === "string" ){
                dataHandler == "yes" ? successHandler( objResponse, override ) : successHandler( override );
            }
        },  
        error: function (jqXHR, XMLHttpRequest, textStatus, errorThrown) { }
     });
}

但这对于如何防止这两个事件触发我的 Ajax 更新的实际问题并没有太大帮助。

【问题讨论】:

  • 我没有看到 Ajax 调用在哪里完成?

标签: javascript jquery event-handling timeout jquery-events


【解决方案1】:

我会尝试像这样设置一个值检查功能:

var $inputIntance = $("#path-to-your-input");
var lastInputValue;

function checkInputValue () {
    var newValue = $inputIntance.val();
    if (newValue != lastInputValue) {
        // make your AJAX call here
        lastInputValue = newValue;
        el = $inputIntance.closest('ul');
        widget[func](dyn, el, lib_template, locale, lastInputValue, "update");
    }
}

然后通过您喜欢的任何用户操作事件触发此检查:

$inputIntance.on('keyup change', function(e) {
    checkInputValue();
}

或者像这样

$inputIntance.on('keyup change', checkInputValue );

更新: 当您必须限制每次 AJAX 请求的数量时,可能会出现这种情况。 我在之前的代码中添加了时间控制功能。您可以在下面找到代码并现场试用here in JSFiddle

$(document).ready(function () {
    var $inputIntance = $("#test-input");
    var lastInputValue;
    var valueCheckTimer;
    var MIN_TIME_BETWEEN_REQUESTS = 100; //100ms
    var lastCheckWasAt = 0;

    function checkInputValue () {
        lastCheckWasAt = getTimeStamp();
        var newValue = $inputIntance.val();
        if (newValue != lastInputValue) {
            // make your AJAX call here
            lastInputValue = newValue;
            $("#output").append("<p>AJAX request on " + getTimeStamp() + "</p>");
            //el = $inputIntance.closest('ul');
            //widget[func](dyn, el, lib_template, locale, lastInputValue, "update");
        }
    }

    function getTimeStamp () {
        return (new Date()).getTime();
    }

    function checkInputValueScheduled() {
        if (valueCheckTimer) { // check is already planned: it will be performed in MIN_TIME_BETWEEN_REQUESTS
            return;
        } else { // no checks planned
            if  ((getTimeStamp() - lastCheckWasAt) > MIN_TIME_BETWEEN_REQUESTS) { // check was more than MIN_TIME_BETWEEN_REQUESTS ago
                checkInputValue();
            } else { // check was not so much time ago - schedule new check in MIN_TIME_BETWEEN_REQUESTS
                valueCheckTimer = window.setTimeout(
                    function () {
                        valueCheckTimer = null;
                        checkInputValue();
                    }, 
                    MIN_TIME_BETWEEN_REQUESTS
                );
            }
        }
    }

    $inputIntance.bind('keyup change', function(e) {
        $("#output").append("<p>input event captured</p>");
        checkInputValueScheduled();
    });
});

【讨论】:

  • 也不错。我试试看
【解决方案2】:

我之前遇到过这个问题,我最终做的是在创建时将请求保存在对象上,并测试先前设置的对象以在必要时中止它。您必须编辑触发 ajax 调用的函数。例如:

if ( ajaxRequest ) { 
  ajaxRequest.abort();
}
ajaxRequest = $.ajax({ ... }); // triggers ajax request and saves it

如果 widget 函数返回一个 ajax 对象,那么您可以将其分配给变量,而不是修改原始 ajax 请求。

【讨论】:

    【解决方案3】:

    除了change,还有什么理由听keyUp?也许真正重要的只是这些事件之一。

    如果没有,我猜你将不得不按照你的建议使用闭包。

    【讨论】:

    • 无论如何,我意识到我的回答给出了一个方向,但这个问题在另一个上下文或其他事件中肯定是有意义的。
    • 对其进行了更多测试。如果我只使用更改,事件触发很晚......就像模糊......所以我会尝试用两个事件来解决问题。
    【解决方案4】:

    好的。我明白了(在尝试了 1000 次之后......)。

    以下是有效的 = 触发先触发的事件,阻止预告片:

    var isEven;
    input.on('keyup change', function(e) {
        isEven = true;
        if (timer) {
            window.clearTimeout(timer);
        }
        timer = window.setTimeout( function() {
            timer = null;
            val = input.val();
            el = input.closest('ul');
            // prevent double firing after interval passed
            if (isEven === true ){
                isEven = false;
            } else {
                isEven = true;
                return;
            }
            widget[func](dyn, el, lib_template, locale, val, "update");
        }, interval );
    });
    

    似乎做了它应该做的。如有错误欢迎指正。

    【讨论】:

    • 具有多个事件或需要相同重复事件的间隔延迟的出色解决方案
    【解决方案5】:

    如果先触发一个,则删除另一个。

    const handler = e => {
      const eventType = e.type === 'mousedown' ? 'click' : 'mousedown';
      window.removeEventListener(eventType, handler);
    };
    
    window.addEventListener('click', handler);
    window.addEventListener('mousedown', handler);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-05
      • 1970-01-01
      • 2019-12-14
      相关资源
      最近更新 更多