Как продолжить распространение событий после отмены?

Когда пользователь нажимает на определенную ссылку, я хотел бы представить их с помощью диалогового окна подтверждения. Если они нажмут "Да", я бы хотел продолжить оригинальную навигацию. Один улов: мой диалог подтверждения реализуется путем возвращения объекта jQuery.Deferred, который разрешен только тогда, когда/если пользователь нажимает кнопку "Да". Таким образом, в основном диалог подтверждения является асинхронным.

Итак, в основном я хочу что-то вроде этого:

$('a.my-link').click(function(e) {
  e.preventDefault(); e.stopPropogation();
  MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
      //continue propogation of e
    })
})

Конечно, я мог бы установить флаг и повторно запускать клик, но это грязно, как черт. Любой естественный способ сделать это?

51
18 окт. '11 в 21:29
источник поделиться
7 ответов

Ниже приведены фрагменты кода, который действительно работал в Chrome 13, к моему удивлению.

function handler (evt ) {
    var t = evt.target;
    ...
    setTimeout( function() {
        t.dispatchEvent( evt )
    }, 1000);
    return false;
}

Это не очень кросс-браузер и, возможно, будет исправлено в будущем, потому что это похоже на риск безопасности, imho.

И я не знаю, что произойдет, если вы отмените распространение события.

9
18 окт. '11 в 23:19
источник

Если я правильно понимаю проблему, я думаю, вы можете просто обновить событие, чтобы быть оригинальным событием в этом закрытии, которое у вас есть. Поэтому просто установите e = e.originalEvent в .done-функцию.

https://jsfiddle.net/oyetxu54/

MyApp.confirm("confirmation?")
.done(function(){ e = e.originalEvent;})

вот скрипка с другим примером (держите консоль открытой, чтобы вы могли видеть сообщения): это сработало для меня в chrome и firefox

3
12 мая '15 в 1:27
источник

Я решил проблему таким образом в одном из моих проектов. Этот пример работает с некоторыми базовыми обработками событий, такими как клики и т.д. Обработчик для подтверждения должен быть связан с первым обработчиком.

    // This example assumes clickFunction is first event handled.
    //
    // you have to preserve called function handler to ignore it 
    // when you continue calling.
    //
    // store it in object to preserve function reference     
    var ignoredHandler = {
        fn: false
    };

    // function which will continues processing        
    var go = function(e, el){
        // process href
        var href = $(el).attr('href');
        if (href) {
             window.location = href;
        }

        // process events
        var events = $(el).data('events');

        for (prop in events) {
            if (events.hasOwnProperty(prop)) {
                var event = events[prop];
                $.each(event, function(idx, handler){
                    // do not run for clickFunction
                    if (ignoredHandler.fn != handler.handler) {
                        handler.handler.call(el, e);
                    }
                });
            }
        }
    }

    // click handler
    var clickFunction = function(e){
        e.preventDefault();
        e.stopImmediatePropagation();
        MyApp.confirm("Are you sure you want to navigate away?")
           .done(go.apply(this, e));
    };

    // preserve ignored handler
    ignoredHandler.fn = clickFunction;
    $('.confirmable').click(clickFunction);

    // a little bit longer but it works :)
2
17 мая '12 в 11:37
источник

У нас есть аналогичное требование в нашем проекте, и это работает для меня. Протестировано в хроме и IE11.

$('a.my-link').click(function(e) {
  e.preventDefault(); 
  if (do_something === true) {
    e.stopPropogation();
    MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
      do_something = false;
      // this allows user to navigate 
      $(e.target).click();
    })
  }

})
0
09 авг. '17 в 13:48
источник

Я решил это:

  • размещение прослушивателя событий на родительском элементе
  • удаление класса из ссылки ТОЛЬКО, когда пользователь подтверждает
  • откат ссылки после удаления класса.

function async() {
  var dfd = $.Deferred();
  
  // simulate async
  setTimeout(function () {
    if (confirm('Stackoverflow FTW')) {
      dfd.resolve();
    } else {
      dfd.reject();
    }
  }, 0);
  
  return dfd.promise();
};

$('.container').on('click', '.another-page', function (e) {
  e.stopPropagation();
  e.preventDefault();
  async().done(function () {
    $(e.currentTarget).removeClass('another-page').click();
  });
});

$('body').on('click', function (e) {
  alert('navigating somewhere else woot!')
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="container">
  <a href="#" class="another-page">Somewhere else</a>
</div>

Причина, по которой я добавил слушателя событий к родительскому элементу, а не к самой ссылке, заключается в том, что событие jQuery on будет привязываться к элементу, пока не будет сказано иначе. Поэтому, даже если элемент не имеет класса another-page, он все еще имеет подключаемый модуль событий, поэтому вы должны использовать event delegation для решения этой проблемы.

GOTCHAS, это очень основано на состоянии. то есть, если вам нужно спросить пользователя EVERYTIME, они нажмут на ссылку, вам придется добавить второго слушателя, чтобы прочитать класс another-page обратно к ссылке. то есть:.

$('body').on('click', function (e) {
  $(e.currentTarget).addClass('another-page');
});

обратите внимание, что вы также можете удалить прослушиватель событий на container, если пользователь принимает, если вы это сделаете, убедитесь, что вы используете события namespace, потому что могут быть другие слушатели в контейнере, которые вы можете случайно удалить. Подробнее см. https://api.jquery.com/event.namespace/.

0
20 мая '15 в 3:27
источник

Я отредактировал твой код. Новые функции, которые я добавил:

  1. Добавлено пространство имен к событию;
  2. После нажатия на элемент событие будет удалено пространством имен;
  3. Наконец, после завершения необходимых действий в разделе "MyApp" продолжайте распространение, вызывая события "щелчка" других элементов.

Код:

$('a.my-link').on("click.myEvent", function(e) {
  var $that = $(this);
  $that.off("click.myEvent");
  e.preventDefault();
  e.stopImmediatePropagation();
  MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
        //continue propogation of e
        $that.trigger("click");
    });
});
0
14 дек. '18 в 9:43
источник

Это непроверено, но может служить обходным путем для вас

$('a.my-link').click(function(e) {
  e.preventDefault(); e.stopPropogation();
  MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
      //continue propogation of e
      $(this).unbind('click').click()
  })
})
-2
18 окт. '11 в 21:46
источник

Посмотрите другие вопросы по меткам или Задайте вопрос