react-contexify右键菜单动态生成
如果菜单数量少,并且没有其他地方需要共用菜单列表,建议参考react-contexify的右键菜单属性disabled不起作用 此文中处理方法相对快捷
关于为何此插件无法根据state动态更新上文中作者已经说明,这里不在赘述
此方法是根据需要展开右键菜单栏目搭配数量无限增加
首先增加菜单数组中的字段用来判断是否显示/禁用
一般情况大概这样
const menu = {
menuId: '2',
items: [
{ key: 1, name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 2, name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 3, name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 4, name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 5, name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 6, name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
],
};
const ContextMenu = () => (
<Menu id={menu.menuId}>
{roleInfoMenu.items.map(item => (
<Item key={item.key} onClick={item.handler}>{item.name}</Item>
))}
</Menu>
);
const { show } = useContextMenu({
id: '2',
});
const handleContextMenu = (event, node) => {
event.preventDefault();
show(event,{
props: node,
});
};
const rightContextMenu = (e, data) => {
e.preventDefault();
handleContextMenu(e, data);
};
return (
<div>
****
{
arr.map(item => {
****
****
<ContextMenu />
});
****
</div>
);
首先修改菜单数组,增加一个字段用来和实际内容状态判断是否需要此菜单
const menu = {
menuId: '2',
items: [
{ key: 1, showStatusArr: [0, 1] name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 2, showStatusArr: [0, 3], name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 3, showStatusArr: [2], name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 4, showStatusArr: [4], name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 5, showStatusArr: [0, 5], name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
{ key: 6, showStatusArr: [5], name: 'xxxx', handler: ({props}) => { xxxxx(props); }},
],
};
然后直接改写ContextMenu的生成逻辑,根据条件判断来生成菜单
******
const ContextMenu = ({Status}) => (
<ContentMenu id={menu.menuId}>
{
menu.items.map(item => {
if(item.showStatusArr instanceof Array && item.showStatusArr.includes(Status)){
return <Item
key={item.key}
onClick={item.handler}
>
{item.name}
</Item>
}
})
}
</ContentMenu>
);
******
return (
<div>
...
{
arr.map(item => {
****
****
<ContextMenu Status={item.Status} />
});
...
</div>
);
此时出来的效果变成 因为Menu所在的DOM id是一样的,N条数据执行完之会把Menu的内容改写为最后一次渲染的,并且还打乱了Menu的布局 于是就想出了为每条记录单独创建一个id的Menu,执行useContextMenu()时动态为其指定id,这样就能保证每条记录对应的菜单栏目是事先根据状态生成好的,达到伪动态的目的 这做法缺点很明显,有几种组合,就要在右键点击时判断几种然后更新state的值,凭空增加了很多无用代码量
const [rightMenuId, setRightMenuId] = useState();
const [rightClickEve, setRightClickEve] = useState();
const [rightClickItem, setRightClickItem] = useState();
useEffect(() => {
if(rightMenuId){
handleContextMenu(rightClickEve, rightClickItem);
}
}, [rightMenuId,rightClickEve]);
const handleMenu = {
draft: 'draftMenu',
submit: 'submitMenu',
reject: 'rejectMenu',
access: 'accessMenu',
public: 'publicMenu',
report: 'reportMenu',
items: [
{ key: 'edit', showStatusArr: [0,2], name: <span><EditOutlined />编辑</span>, handler: ({props}) => { rightContentClick({key: 'edit', item: {props}}) }},
{ key: 'submit', showStatusArr: [0,2], name: <span><CheckOutlined />提交</span>, handler: ({props}) => { rightContentClick({key: 'submit', item: {props}}) }},
{ key: 'delete', showStatusArr: [0,5], name: <span style={{color: 'red'}}><DeleteOutlined />删除</span>, handler: ({props}) => { rightContentClick({key: 'delete', item: {props}}) }},
{ key: 'rollback', showStatusArr: [1], name: <span><RollbackOutlined />撤销</span>, handler: ({props}) => { rightContentClick({key: 'rollback', item: {props}}) }},
{ key: 'showReason', showStatusArr: [2, 5], name: <span><EyeOutlined />查看原因</span>, handler: ({props}) => { rightContentClick({key: 'showReason', item: {props}}) }},
{ key: 'public', showStatusArr: [3], name: <span><NodeExpandOutlined />上架</span>, handler: ({props}) => { rightContentClick({key: 'public', item: {props}}) }},
{ key: 'reEdit', showStatusArr: [3], name: <span style={{color: 'red'}}><EditOutlined />重新修改</span>, handler: ({props}) => { rightContentClick({key: 'reEdit', item: {props}}) }},
{ key: 'cancel', showStatusArr: [4], name: <span><NodeCollapseOutlined />下架</span>, handler: ({props}) => { rightContentClick({key: 'cancel', item: {props}}) }},
{ key: 'update', showStatusArr: [4], name: <span><ArrowUpOutlined />升级模板</span>, handler: ({props}) => { rightContentClick({key: 'update', item: {props}}) }},
{ key: 'appeal', showStatusArr: [5], name: <span><SoundOutlined />申诉</span>, handler: ({props}) => { rightContentClick({key: 'appeal', item: {props}}) }},
{ key: 'history', showStatusArr: [0,1,2,3,4,5], name: <span style={{color: '#b99c00'}}><HistoryOutlined />操作历史</span>, handler: ({props}) => { rightContentClick({key: 'history', item: {props}}) }},
],
};
const ContextMenu = ({divId, templateStatus}) => (
<ContentMenu id={divId}>
{
handleMenu.items.map(item => {
if(item.showStatusArr instanceof Array && item.showStatusArr.includes(templateStatus)){
return <Item
key={item.key}
onClick={item.handler}
>
{item.name}
</Item>
}
})
}
</ContentMenu>
);
const { show } = useContextMenu({
id: rightMenuId,
});
const handleContextMenu = (event, node) => {
event.preventDefault();
show(event,{
props: node,
});
};
const onRightClick = (e, item) => {
e.preventDefault();
if(item.templateStatus === 0){
setRightMenuId(handleMenu.draft);
}else if(item.templateStatus === 1){
setRightMenuId(handleMenu.submit);
}else if(item.templateStatus === 2){
setRightMenuId(handleMenu.reject);
}else if(item.templateStatus === 3){
setRightMenuId(handleMenu.access);
}else if(item.templateStatus === 4){
setRightMenuId(handleMenu.public);
}else if(item.templateStatus === 5){
setRightMenuId(handleMenu.report);
}else{
setRightMenuId(handleMenu.draft)
}
};
const generatorDivId = (templateStatus) => {
if(templateStatus === 0){
return handleMenu.draft;
}else if(templateStatus === 1){
return handleMenu.submit;
}else if(templateStatus === 2){
return handleMenu.reject;
}else if(templateStatus === 3){
return handleMenu.access;
}else if(templateStatus === 4){
return handleMenu.public;
}else if(templateStatus === 5){
return handleMenu.report;
}else{
return handleMenu.draft;
}
};
return (
<div>
...
{
arr.map(item => {
<div onContextMenu={(e) => onRightClick(e, item)} title='右键点击展开操作菜单'>
****
****
<ContextMenu divId={generatorDivId(item.templateStatus)} templateStatus={item.templateStatus} />
</div>
});
...
</div>
);
效果如下 方式不是很优美,不过好歹满足了要求,还是开头第一句话,如果菜单本身数量少,菜单列表也无需json格式的话采取开头文章中作者的方法更简单快捷。
|