0.1.0-beta.1 • Published 7 months ago

context-menu-common-react v0.1.0-beta.1

Weekly downloads
-
License
-
Repository
-
Last release
7 months ago

通用右键菜单

前端经常有用到右键菜单扩展交互能力的需求,不同场景下菜单功能不同,且通常需要根据右键目标的不同显示不同的菜单操作,本文就记录了一种通用的右键菜单解决方案。

Get Started

按开发环境的要求,运行和调试项目

运行和调试组件

pnpm run dev

运行测试用例

pnpm run test

按照社区规范和最佳实践,生成构建产物

pnpm run build

继续创建更多项目要素

pnpm run new

用法

简介

demo演示链接: 右键菜单演示demo

  • 每个菜单项都可以设置是否禁用、是否隐藏
  • 支持子菜单
  • 支持显示icon图标、提示语、快捷键等
  • 与业务完全解耦,通过简单配置即可定制出功能各异的菜单

样图演示: image.png

用法

1. 最简单的用法

import { ContextMenu, IContextMenuItem } from 'context-menu-common-react';

// 菜单配置数据
const menuList: IContextMenuItem[] = [
  { text: '复制', key: 'copy' },
  { text: '粘贴', key: 'paste', shortcutKeyDesc: `${cmd}+V` },
  {
    text: '对齐',
    key: 'align',
    children: [
      { text: '水平垂直居中', key: 'horizontalVerticalAlign' },
      { text: '水平居中', key: 'horizontalAlign' },
    ],
 },
];

export () => {
  const containerDomRef = React.useRef();
  // 菜单点击触发
  const handleMenuTrigger = (menu: IContextMenuItem) => {
      console.log(menu); // { text: '复制', key: 'copy' }
      // 这里处理触发菜单后的逻辑....

  };
  return (
    <div
      ref={containerDomRef}
      style={{ position: 'relative' }}>
      <ContextMenu
        getContainerDom={() => containerDomRef.current}
        menuList={menuList}
        onTrigger={handleMenuTrigger}
      />
    </div>
  );
};

2. 根据右键目标动态控制是否禁用和隐藏

import { ContextMenu, IContextMenuItem } from 'context-menu-common-react';

// 菜单配置数据
const menuList: IContextMenuItem[] = [
  {
    text: '复制',
    key: 'copy',
    // 动态判断是否禁用
    disable: (ctx) => ctx.event.target?.getAttribute('id') === 'button',
  },
  {
    text: '粘贴',
    key: 'paste',
    // 动态判断是否隐藏
    hide: (ctx) => ctx.event.target?.getAttribute('id') === 'text',
  },
];

3. 为判断函数注入更多上下文数据

  • mergeContextFromEvent 函数会在每次唤起右键菜单前运行一次,其返回值会融合进入disable hide等菜单属性函数的参数,作为ctx上下文用来辅助判断
import { ContextMenu, IContextMenuItem } from 'context-menu-common-react';

// 菜单配置数据
const menuList: IContextMenuItem[] = [
  {
    text: '复制',
    key: 'copy',
    // 动态判断是否禁用
    disable: (ctx) => ctx.event.target?.getAttribute('id') === 'button',
  },
];
export () => {
  const containerDomRef = React.useRef();
  const selectedNodeRef = useRef(null);
  // 菜单点击触发
  const handleMenuTrigger = (menu: IContextMenuItem) => {
      console.log(menu); // { text: '复制', key: 'copy' }
      // 这里处理触发菜单后的逻辑....

  };
  const mergeContext = () => {
    const id = selectedNodeRef.current?.getAttribute('id');
    return {
      id,
      selectedNode: selectedNodeRef.current, // 也可以传ref等值
    };
  };
  return (
    <div
      ref={containerDomRef}
      style={{ position: 'relative' }}>
      {/* 这里随便渲染一些节点 */}
      {[1,2,3].map(e => <div id={e}>node:{e}</div>)}
      <ContextMenu
        getContainerDom={() => containerDomRef.current}
        menuList={menuList}
        onTrigger={handleMenuTrigger}
        mergeContextFromEvent={mergeContext}
      />
    </div>
  );
};

4. text、childen等字段都可以设为动态值以满足复杂场景

// 菜单配置数据
const menuList: IContextMenuItem[] = [
  {
    // 显示动态文本
    text: (ctx) => ctx.event.target?.getAttribute('id') === 'button' ? '复制按钮' : '复制',
    key: 'copy',
  },
  {
    text: '对齐',
    key: 'align',
    children: (ctx) => {
      const arr =[
        { text: '水平垂直居中', key: 'horizontalVerticalAlign' },
        { text: '水平居中', key: 'horizontalAlign' },
      ];
      // 某个判断逻辑可以控制子节点是否展示等
      if (ctx..event.target?.getAttribute('id') === 'button') {
	arr = [];
      }
      return arr;
   },
];