Pio*_*rak 13 javascript-events reactjs
我正在创建出现在屏幕顶部的菜单.当用户点击其中一个菜单项div时会出现很多链接.我不能通过点击另一个菜单项(没问题,已经实现它)来隐藏这个div,而且还可以点击其他任何地方然后点击这个div和menuitems.
我听说过两个解决方案:
第一个对我不好,因为该div将覆盖页面上的链接,我希望它们即使在点击menuitem后也可以点击,并且它出现了相应的div.所以我尝试了第二次灵魂.但问题是在我的组件的处理程序之前触发了body上的jquery click处理程序.我不知道如何让它首先调用我的组件处理程序,然后阻止事件传播.
这是代码和js小提琴:
/** @jsx React.DOM */
var Menu = React.createClass({
click: function(e) {
console.log('component handled click - should be called before jquery one and prevent jquery handler from running at all');
e.stopPropagation();
},
render: function(){
console.log("component renders");
return (
<div>
<div>| MenuItem1 | MenuItem2 | MenuItem 3 |</div>
<br />
<div className="drop">
MenuItem 1 (This div appears when you click menu item)
<ul>
<li><a href="#" onClick={this.click}>Item 1 - when I click this I don't want document.body.click to fire</a></li>
<li><a href="#" onClick={this.click}>Item 1 - when I click this I don't want document.body.click to fire</a></li>
</ul>
</div>
</div>
);
}
});
React.renderComponent(<Menu />, document.getElementById("menu"));
$(document).ready(function() {
console.log('document is ready');
$("body").click(function() {
console.log('jquery handled click - should not happen before component handled click');
});
});
Run Code Online (Sandbox Code Playgroud)
在运行它之前启动控制台以解释问题
Pio*_*rak 16
所以我解决了.使用jQuery向文档添加事件处理程序时,将首先触发此事件处理程序.所以你无法捕捉事件并阻止它的传播.但是当你使用document.addEventlistener附加处理程序时,这个处理程序最后被调用,你有机会反应:)点击React组件.
我修改了Mike的代码以使其工作(http://jsfiddle.net/s8hmstzz/):
/** @jsx React.DOM */
var Menu = React.createClass({
getInitialState: function() {
return {
show: true
}
},
componentDidMount: function() {
// when attaching with jquery this event handler is run before other handlers
//$('body').bind('click', this.bodyClickHandler);
document.addEventListener('click', this.bodyClickHandler);
},
componentWillUnmount: function() {
//$('body').unbind('click', this.bodyClickHandler);
document.removeEventListener('click', this.bodyClickHandler);
},
anchorClickHandler: function(e) {
console.log('click on anchor - doing some stuff and then stopping propation');
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
},
bodyClickHandler: function(e) {
console.log('bodyclickhandler');
this.setState({show: false})
},
clickHandler: function(e) {
// react to click on menu item
},
preventEventBubbling: function(e) {
console.log('click on div - stopping propagation');
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
},
render: function() {
return (
<div>
<a href="#" onClick={this.anchorClickHandler}>Link - will stop propagation</a>
<div id="menudrop" onClick={this.preventEventBubbling} style={{display: this.state.show ? 'block' : 'none'}}>
<ul>
<li onClick={this.clickHandler}>Menu Item</li>
</ul>
</div>
</div>
)
}
});
React.renderComponent(<Menu />, document.getElementById('menu'));
Run Code Online (Sandbox Code Playgroud)
启动控制台,然后单击div,anchor和body以查看其工作原理.我不知道为什么使用addEventListener而不是jQuery更改事件处理程序的触发顺序.
请参阅上面的评论.
基本上onClick
,当结合使用jquery(或普通的JS事件)时,你不能依赖于能够像React 一样停止传播事件.
您可以做的是检查您的$('body').click()
功能,即您没有点击菜单(因此单击其中的项目后它不会关闭您的菜单).另外值得注意的是,你应该在反应组件中绑定这个主体事件,这样你就可以通过安装组件来干净地添加/删除它,而不会让组件本身不知道的任何东西显着改变组件的功能. .
所以你做的是这样的(nb:未经测试的代码,但基于我对同一问题的组件)
var Menu = React.createClass({
getInitialState: function() {
return {
show: true
}
},
componentDidMount: function() {
$('body').bind('click', this.bodyClickHandler);
},
componentWillUnmount: function() {
$('body').unbind('click', this.bodyClickHandler);
},
bodyClickHandler: function(e) {
if ($(e.target).parents('div').get(0) !== this.getDOMNode()) {
this.setState({
show: false
})
}
},
clickHandler: function(e) {
// react to click on menu item
},
render: function() {
return (
<div style={{display: this.state.show ? 'block' : 'none'}}>
<ul>
<li onClick={this.clickHandler}>Menu Item</li>
</ul>
</div>
)
}
});
Run Code Online (Sandbox Code Playgroud)
因此,在上面的代码中,我们假设您希望在组件安装到dom后立即显示菜单下拉列表.这可能不是这种情况,因为您可能希望安装组件,然后根据悬停显示/隐藏它.在这种情况下,只需要在显示菜单的任何地方将$('body').bind()
事件绑定从componentDidMount
回调移动到回调.$('body').unbind()
应该在组件被隐藏时移动到.然后你会得到一个完美的情况,当菜单显示时,我们绑定一个等待点击的身体事件,并在它被隐藏和/或卸载时取消绑定.
发生的是在点击菜单bodyClickHandler
之前调用clickHandler
的,但是bodyClickHandler
如果你点击的父树不包含div
我们组件的根,则只隐藏菜单(this.getDOMNode()
在render()
返回时给出根节点的html元素).
因此,在组件外部单击将关闭它,单击组件内部将不执行任何操作,单击<li>
将触发clickHandler
.一切按预期工作.
希望这可以帮助.
归档时间: |
|
查看次数: |
11282 次 |
最近记录: |