development

취소 후 이벤트 전파를 계속하는 방법은 무엇입니까?

big-blog 2020. 12. 9. 21:09
반응형

취소 후 이벤트 전파를 계속하는 방법은 무엇입니까?


사용자가 특정 링크를 클릭하면 확인 대화 상자를 표시하고 싶습니다. "예"를 클릭하면 원래 탐색을 계속하겠습니다. 한 가지 캐치 : 내 확인 대화 상자는 사용자가 예 버튼을 클릭 할 때만 해결되는 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
    })
})

물론 플래그를 설정하고 클릭을 다시 트리거 할 수는 있지만 그것은 지저분합니다. 이렇게하는 자연스러운 방법이 있습니까?


아래는 놀랍게도 Chrome 13에서 실제로 작동 한 코드의 일부입니다.

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

이것은 매우 크로스 브라우저가 아니며 보안 위험이있는 것처럼 느껴지므로 향후 수정 될 수 있습니다.

이벤트 전파를 취소하면 어떻게되는지 모르겠습니다.


내 프로젝트 중 하나에서 이런 식으로 문제를 해결했습니다. 이 예제는 클릭 등과 같은 몇 가지 기본 이벤트 처리와 함께 작동합니다. 확인을위한 핸들러는 첫 번째 핸들러 바인딩이어야합니다.

    // 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 :)

문제를 올바르게 이해하고 있다면 해당 이벤트를 종료하여 원래 이벤트로 업데이트 할 수 있다고 생각합니다. 따라서 .done 함수에서 e = e.originalEvent를 설정하십시오.

https://jsfiddle.net/oyetxu54/

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

여기에 다른 예제가있는 바이올린이 있습니다 (메시지를 볼 수 있도록 콘솔을 열어 두십시오). 이것은 크롬과 파이어 폭스에서 저에게 효과적이었습니다.


나는 그것이 위험 할 수 있다고 생각하지만 (!) 적어도 글을 쓰는 시점에서는 작동하는 것 같습니다.

이것은 ES6 및 React이며 테스트를 거쳐 아래 브라우저에서 작동하는 것으로 나타났습니다. 한 가지 보너스는 예외가있는 경우 (이를 만드는 동안 몇 가지가 있음) 일반 <a>링크 처럼 링크로 이동하지만 SPA가 아닌 경우 ofc입니다.

데스크탑 :

  • 크롬 v.76.0.3809.132
  • Safari v.12.1.2
  • Firefox Quantum v.69.0.1
  • 가장자리 18
  • 에지 17
  • IE11

모바일 / 태블릿 :

  • Android v.8 삼성 인터넷
  • Android v.8 Chrome
  • Android v.9 Chrome
  • iOs11.4 사파리
  • iOS12.1 사파리

.

import 'mdn-polyfills/MouseEvent'; // for IE11
import React, { Component } from 'react';
import { Link } from 'react-router-dom';

class ProductListLink extends Component {
  constructor(props) {
    super(props);
    this.realClick = true;

    this.onProductClick = this.onProductClick.bind(this);
  }

  onProductClick = (e) => {
    const { target, nativeEvent } = e;
    const clonedNativeEvent = new MouseEvent('click', nativeEvent);

    if (!this.realClick) {
      this.realClick = true;
      return;
    }

    e.preventDefault();
    e.stopPropagation();

    // @todo what you want before the link is acted on here

    this.realClick = false;
    target.dispatchEvent(clonedNativeEvent);
  };

  render() {
    <Link
      onClick={(e => this.onProductClick(e))}
    >
      Lorem
    </Link>  
  }
}

나는 이것을 다음과 같이 해결했다.

  1. 상위 요소에 이벤트 리스너 배치
  2. 사용자가 확인한 경우에만 링크에서 클래스 제거
  3. 수업을 제거한 후 링크를 ​​다시 클릭합니다.

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>

The reason I added the event listener to the parent and not the link itself is because the jQuery's on event will bind to the element until told otherwise. So even though the element does not have the class another-page it still has the event listener attached thus you have to take advantage of event delegation to solve this problem.

GOTCHAS this is very state based. i.e. if you need to ask the user EVERYTIME they click on a link you'll have to add a 2nd listener to readd the another-page class back on to the link. i.e.:

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

side note you could also remove the event listener on container if the user accepts, if you do this make sure you use namespace events because there might be other listeners on container you might inadvertently remove. see https://api.jquery.com/event.namespace/ for more details.


We have a similar requirement in our project and this works for me. Tested in chrome and 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();
    })
  }

})

I edited your code. New features that I added:

  1. Added namespace to event;
  2. After click on element event will be removed by namespace;
  3. Finally, after finish needed actions in "MyApp" section continue propagation by triggering others element "click" events.

Code:

$('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");
    });
});

This is untested but might serve as a workaround for you

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

참고URL : https://stackoverflow.com/questions/7811959/how-to-continue-event-propagation-after-cancelling

반응형