取消事件后如何继续事件传播
How to continue event propagation after cancelling?
当用户单击某个链接时,我想向他们展示一个确认对话框。如果他们点击"是",我想继续原来的导航。注意:我的确认对话框是通过返回一个jQuery来实现的。延迟对象,只有当/当用户单击Yes按钮时才解析。确认对话框是异步的
所以我想要这样写:$('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;
}
这不是很跨浏览器,也许会在未来修复,因为它感觉像安全风险,恕我直言。
我不知道会发生什么,如果你取消事件传播。
这可能有风险,但至少在编写时似乎可行,我们正在生产中使用它。
这是ES6和React,我已经测试并发现它适用于以下浏览器。一个额外的好处是,如果有一个异常(在此过程中有一对),它会像正常的<a>
链接一样进入链接,但它不会是SPA,然后是ofc。
- Chrome 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 Safari
- iOs12.1 Safari
.
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>
}
}
在我的一个项目中,我用这种方法解决了一个问题。这个例子与一些基本的事件处理,如点击等。用于确认的处理程序必须是第一个绑定的处理程序。
// 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 = . originalevent。
https://jsfiddle.net/oyetxu54/MyApp.confirm("confirmation?")
.done(function(){ e = e.originalEvent;})
这里是一个不同的例子(保持控制台打开,这样你就可以看到消息):
我解决了这个问题:
- 在父元素上放置事件监听器
- 仅当用户确认 时才从链接中删除类
- 删除类后重新点击链接。
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这是基于状态的。例如,如果你需要询问用户每次他们点击链接,你将不得不添加第二个监听器来读取another-page
类回到链接。例如:
$('body').on('click', function (e) {
$(e.currentTarget).addClass('another-page');
});
边注如果用户接受,您还可以删除container
上的事件侦听器,如果您这样做,请确保使用namespace
事件,因为您可能无意中删除了容器上的其他侦听器。详见https://api.jquery.com/event.namespace/
在我们的项目中有类似的要求,这对我来说是有效的。在chrome和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();
})
}
})
我编辑你的代码。我添加的新功能:
- 点击后元素事件将被命名空间移除;
- 最后,在"MyApp"部分完成所需动作后,通过触发其他元素的"click"事件继续传播。
代码:
$('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");
});
});
这是未经测试的,但可以作为您的解决方案
$('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()
})
})
- 分派点击事件并保留击键修饰符
- 模糊事件的Javascript测试
- 将单击事件附加到按钮或链接上的类,该按钮或链接会触发 AJAX 帖子,然后延迟并继续原始操作
- 事件侦听器调用函数后,代码的执行在哪里继续
- onClick 事件,但仍继续执行 href 目标
- HTML5迷宫游戏-如果触摸事件继续,碰撞检测后该怎么办
- 继续拖动事件,而不拖动超过任意阈值的元素
- 等待第一个事件完成,然后继续使用document.ready代码
- 捕获提交事件,验证,如果可以,则继续提交表单
- 取消鼠标悬停事件的有效方法.继续往下读,看看为什么
- 如何仅在所有onClick事件完成后继续
- 等待事件被处理以继续执行触发该事件的函数
- 取消事件后如何继续事件传播
- HTML页面在点击事件后继续重新加载
- 如何在dojo中创建等待事件,等待用户在继续之前单击按钮
- 必应地图pin's拖拽成功,但必应地图移动事件继续
- Javascript:取消或让事件继续
- Javascript要等到回调中最后一个事件触发后才继续
- 如何“;继续尝试,直到成功为止“;使用事件驱动模型
- 尽管调用了off(),事件仍在继续处理