Javascript ReactJS和非分层组件
我一直在研究ReactJS中的上下文菜单模块,它让我思考如何处理非层次化组件 我遇到的问题是,应用程序中的许多不同项可能需要使用上下文菜单。通常在React中,您会将父对象的回调传递给需要与父对象通信的子对象。例如,我的第一个想法是让一个openContextMenumousePosition,optionsObject函数从我的ContextMenu类传递给所有希望在右键单击时显示上下文菜单的元素 但对于所有这些元素,甚至任何元素都是上下文菜单的子元素,这是没有意义的!相对于应用程序的其他组件,上下文菜单不是分层的。在Angular中,我可能会编写一个ContextMenu服务,如果组件想要访问这样一个菜单,它们就需要该服务Javascript ReactJS和非分层组件,javascript,contextmenu,reactjs,Javascript,Contextmenu,Reactjs,我一直在研究ReactJS中的上下文菜单模块,它让我思考如何处理非层次化组件 我遇到的问题是,应用程序中的许多不同项可能需要使用上下文菜单。通常在React中,您会将父对象的回调传递给需要与父对象通信的子对象。例如,我的第一个想法是让一个openContextMenumousePosition,optionsObject函数从我的ContextMenu类传递给所有希望在右键单击时显示上下文菜单的元素 但对于所有这些元素,甚至任何元素都是上下文菜单的子元素,这是没有意义的!相对于应用程序的其他组件
这是应该使用全局事件处理程序的情况吗?我是不是完全错了?如何处理组件之间的这种水平交互?上下文菜单非常特殊。任何时候都不应打开多个上下文菜单。它们也很特别,因为它可以从任何地方打开。试着弄清楚当把它们放在一起时是什么样子的 为了解决我们的全局问题,我们将创建一个mixin,其中封装一个私有事件发射器
var menuEvents = new events.EventEmitter();
var ContextMenuMixin = {
// this.openContextMenu(['foo', 'bar'], (err, choice) => void)
openContextMenu: function(options, callback){
menuEvents.emit('open', {
options: options,
callback: callback
});
},
closeContextMenu: function(){
menuEvents.emit('close');
}
};
现在对于组件,我们需要做一些事情。这里是初始化部分。只是绑定到一些事件,以及轻量级鼠标跟踪
var mouse = {x: 0, y: 0};
var updateMouse = function(e){
mouse.x = e.pageX;
mouse.y = e.pageY;
};
var ContextMenu = React.createClass({
getInitialState: function(){
return {options: null, callback: null};
},
componentDidMount: function(){
menuEvents.addListener('open', this.handleOpenEvent);
menuEvents.addListener('close', this.closeMenu);
addEventListener('mousemove', updateMouse);
},
这些事件处理程序非常简单。HandLeopBenEvent只将事件有效负载和鼠标位置存储在状态中,这将有效地锁定鼠标位置,直到下一次打开它为止。而对应方只是重置状态,并调用带有错误的回调
handleOpenEvent: function(payload){
this.setState(_.merge({}, payload, mouse));
},
closeMenu: function(){
if (this.state.callback) {
this.replaceState(this.getInitialState());
this.state.callback(new Error('no selection made'));
}
},
最后,我们呈现传递给事件的选项列表,并为每个选项创建单击处理程序
render: function(){
if (!this.state.options) {
return <div />
}
var style = {
left: this.state.x,
top: this.state.y,
position: 'fixed'
};
return (
<div className="react-contextmenu" style={style}>
<ul className="react-contextmenu-options">
{this.state.options.map(function(x, i){
return <li key={i}
onClick={this.makeClickHandler(x)}>
{x}
</li>
}, this)}
</ul>
</div>
);
},
makeClickHandler: function(option){
return function(){
if (this.state.callback) {
this.state.callback(null, option);
this.replaceState(this.getInitialState());
}
}.bind(this);
}
上下文菜单很特别。任何时候都不应打开多个上下文菜单。它们也很特别,因为它可以从任何地方打开。试着弄清楚当把它们放在一起时是什么样子的 为了解决我们的全局问题,我们将创建一个mixin,其中封装一个私有事件发射器
var menuEvents = new events.EventEmitter();
var ContextMenuMixin = {
// this.openContextMenu(['foo', 'bar'], (err, choice) => void)
openContextMenu: function(options, callback){
menuEvents.emit('open', {
options: options,
callback: callback
});
},
closeContextMenu: function(){
menuEvents.emit('close');
}
};
现在对于组件,我们需要做一些事情。这里是初始化部分。只是绑定到一些事件,以及轻量级鼠标跟踪
var mouse = {x: 0, y: 0};
var updateMouse = function(e){
mouse.x = e.pageX;
mouse.y = e.pageY;
};
var ContextMenu = React.createClass({
getInitialState: function(){
return {options: null, callback: null};
},
componentDidMount: function(){
menuEvents.addListener('open', this.handleOpenEvent);
menuEvents.addListener('close', this.closeMenu);
addEventListener('mousemove', updateMouse);
},
这些事件处理程序非常简单。HandLeopBenEvent只将事件有效负载和鼠标位置存储在状态中,这将有效地锁定鼠标位置,直到下一次打开它为止。而对应方只是重置状态,并调用带有错误的回调
handleOpenEvent: function(payload){
this.setState(_.merge({}, payload, mouse));
},
closeMenu: function(){
if (this.state.callback) {
this.replaceState(this.getInitialState());
this.state.callback(new Error('no selection made'));
}
},
最后,我们呈现传递给事件的选项列表,并为每个选项创建单击处理程序
render: function(){
if (!this.state.options) {
return <div />
}
var style = {
left: this.state.x,
top: this.state.y,
position: 'fixed'
};
return (
<div className="react-contextmenu" style={style}>
<ul className="react-contextmenu-options">
{this.state.options.map(function(x, i){
return <li key={i}
onClick={this.makeClickHandler(x)}>
{x}
</li>
}, this)}
</ul>
</div>
);
},
makeClickHandler: function(option){
return function(){
if (this.state.callback) {
this.state.callback(null, option);
this.replaceState(this.getInitialState());
}
}.bind(this);
}
你能提供你的代码让我们更好地了解你的困境吗?你能提供你的代码让我们更好地了解你的困境吗?非常酷!这是一个版本的演示,它有一个有效的EventEmitter库和下划线,因此可以在预览窗格中工作。嗯,看起来那个垃圾箱没被救出来。我看到控制台中没有定义EventEmitter2。我对React不太熟悉,但这是否泄漏了从未解除绑定的事件侦听器?可能会,但ContextMenu旨在永不解除绑定。jsbin中的示例显示它是主组件的最后一个直接子组件,它应该位于或安装到主体末尾的自己的节点上。我应该清理它们以确保正确性,但除非您做了其他非常错误的事情,否则它不会显示出来。var EventEmitter2=require'EventEmitter2'。EventEmitter2;var menuEvents=neweventemitter2;很酷!这是一个版本的演示,它有一个有效的EventEmitter库和下划线,因此可以在预览窗格中工作。嗯,看起来那个垃圾箱没被救出来。我看到控制台中没有定义EventEmitter2。我对React不太熟悉,但这是否泄漏了从未解除绑定的事件侦听器?可能会,但ContextMenu旨在永不解除绑定。jsbin中的示例显示它是主组件的最后一个直接子组件,它应该位于或安装到主体末尾的自己的节点上。我应该清理它们以确保正确性,但除非您做了其他非常错误的事情,否则它不会显示出来。var EventEmitter2=require'EventEmitter2'。EventEmitter2;var menuEvents=neweventemitter2;