ben*_*ich 1 javascript contextmenu reactjs
我一直在研究ReactJS中的上下文菜单模块,它让我思考如何处理非分层组件.
我遇到的问题是应用程序中的许多不同项可能想要使用上下文菜单.通常在React中,您将从父对象的回调传递给需要与父进程通信的子进程.例如,我的第一个想法是将一个openContextMenu(mousePosition, optionsObject)函数从我的ContextMenu类传递给所有想要在右键单击上显示上下文菜单的元素.
但是对于所有这些元素(或者甚至可能是任何元素)来说,上下文菜单的孩子都没有意义!相对于应用程序的其他组件,上下文菜单不是分层的.在Angular中,ContextMenu如果他们想要访问这样的菜单,我可能会编写一个所需组件的服务.
这是一种应该使用全局事件处理程序的情况吗?我觉得这一切都错了吗?在组件之间处理这种水平交互的React方法是什么?
上下文菜单很特别.任何时候都不应该打开多个上下文菜单.它们也很特别,因为它可以从任何地方打开.试试这个演示,了解它在组合时的外观.
为了解决我们的全局问题,我们将创建一个包装私有事件发射器的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');
}
};
Run Code Online (Sandbox Code Playgroud)
现在对于组件,我们需要做一些事情.这是初始化部分.只是绑定到一些事件,以及轻量级鼠标跟踪.
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);
},
Run Code Online (Sandbox Code Playgroud)
这些事件处理程序非常简单.handleOpenEvent只是将事件有效负载和鼠标位置存储在状态中,这有效地锁定了鼠标位置,直到它下一次打开.对应方只是重置状态,并以错误调用回调.
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'));
}
},
Run Code Online (Sandbox Code Playgroud)
最后,我们渲染传递给事件的选项列表,并为每个选项创建单击处理程序.
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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1847 次 |
| 最近记录: |