HarmonyOS ArkWeb 系列之文本选中菜单定制:editMenuOptions 深度解析

文章目录

      • [和 onContextMenuShow 有什么区别?](#和 onContextMenuShow 有什么区别?)
      • [核心概念:TextMenuItem 和 TextMenuItemId](#核心概念:TextMenuItem 和 TextMenuItemId)
      • 文本菜单定制流程
      • 完整示例代码
      • [`textRange` 是什么](#textRange 是什么)
      • [系统内置 TextMenuItemId 一览](#系统内置 TextMenuItemId 一览)
      • 几个注意点
      • [和 `editMenuOptions` 对比:bindSelectionMenu](#和 editMenuOptions 对比:bindSelectionMenu)
      • 写在最后

选中网页里的文字,上面弹出一排小按钮(复制、剪切、粘贴......)------这排按钮叫"文本选中菜单"。editMenuOptions 让你完全控制这里出现什么。

和 onContextMenuShow 有什么区别?

别搞混:

  • onContextMenuShow:长按触发,适合图片、链接的右键菜单
  • editMenuOptions:选中文字后弹出的那一排操作按钮

两个是不同场景,API 也完全不同。

核心概念:TextMenuItem 和 TextMenuItemId

大白话解释:

TextMenuItem 就是菜单里的一个按钮,有三个属性:

  • content:显示的文字或图标资源
  • id:这个按钮的唯一标识,用来区分是哪个按钮被点了
  • icon(可选):按钮旁边的小图标

TextMenuItemId 是系统内置的 ID 枚举,用 TextMenuItemId.CUTTextMenuItemId.COPY 这样的方式引用系统默认按钮。自定义按钮用 TextMenuItemId.of('你的自定义ID') 创建。

文本菜单定制流程

完整示例代码

typescript 复制代码
import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebTextMenuDemo {
  controller: webview.WebviewController = new webview.WebviewController();

  // onCreateMenu:决定菜单里放哪些按钮
  // 参数 menuItems 是系统默认的全部菜单项数组
  onCreateMenu(menuItems: Array<TextMenuItem>): Array<TextMenuItem> {
    // 第一步:从系统菜单里只保留我们想要的
    let items = menuItems.filter((menuItem) => {
      return (
        menuItem.id.equals(TextMenuItemId.CUT) ||
        menuItem.id.equals(TextMenuItemId.COPY) ||
        menuItem.id.equals(TextMenuItemId.PASTE)
      );
    });

    // 第二步:添加自定义菜单项
    let shareItem: TextMenuItem = {
      content: '分享',
      id: TextMenuItemId.of('action_share'),
      icon: $r('app.media.share_icon') // 替换为实际图标资源
    };

    let translateItem: TextMenuItem = {
      content: '翻译',
      id: TextMenuItemId.of('action_translate'),
      icon: $r('app.media.translate_icon')
    };

    // 在末尾追加自定义项
    items.push(shareItem);
    items.push(translateItem);

    return items;
  }

  // onMenuItemClick:某个菜单项被点击时的回调
  // 返回 true = 拦截(系统默认行为不执行)
  // 返回 false = 不拦截(系统默认行为照常执行)
  onMenuItemClick(menuItem: TextMenuItem, textRange: TextRange): boolean {
    if (menuItem.id.equals(TextMenuItemId.CUT)) {
      // 剪切:先做自己的逻辑,再拦截系统行为
      console.info('用户剪切了文字,范围:', textRange.start, '-', textRange.end);
      return false; // false = 系统剪切照常执行
    }

    if (menuItem.id.equals(TextMenuItemId.COPY)) {
      console.info('用户复制了文字');
      return false; // 不拦截,让系统正常复制
    }

    if (menuItem.id.equals(TextMenuItemId.of('action_share'))) {
      // 自定义分享逻辑
      console.info('用户点了分享');
      // ... 调用分享面板
      return true; // true = 菜单保持不关闭(适合需要二级操作的情况)
    }

    if (menuItem.id.equals(TextMenuItemId.of('action_translate'))) {
      console.info('用户点了翻译');
      // ... 调用翻译服务
      return true;
    }

    return false; // 默认不拦截
  }

  // 把两个回调封装成 EditMenuOptions 对象
  @State editMenuOptions: EditMenuOptions = {
    onCreateMenu: this.onCreateMenu,
    onMenuItemClick: this.onMenuItemClick
  };

  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
        .editMenuOptions(this.editMenuOptions) // 挂载自定义菜单配置
        .width('100%')
        .height('100%')
    }
  }
}

textRange 是什么

onMenuItemClick 的第二个参数 textRange 包含用户选中的文字范围:

typescript 复制代码
interface TextRange {
  start?: number;  // 选中起始位置(字符索引)
  end?: number;    // 选中结束位置(字符索引)
}

你可以用这个范围去 JS 层获取对应的选中文本(配合 runJavaScript 注入脚本)。

系统内置 TextMenuItemId 一览

ID 说明
TextMenuItemId.CUT 剪切
TextMenuItemId.COPY 复制
TextMenuItemId.PASTE 粘贴
TextMenuItemId.SELECT_ALL 全选
TextMenuItemId.SHARE 分享
TextMenuItemId.TRANSLATE 翻译(部分系统支持)
TextMenuItemId.SEARCH 搜索

几个注意点

1. onCreateMenu 里修改数组顺序就是修改显示顺序

unshift 往前插、用 push 往后加,菜单按你返回的数组顺序排列。

2. 自定义项点击后 truefalse 的区别

对于自定义 ID 的按钮,true 表示点击后不关闭菜单 (适合多步操作),false 表示点击后菜单自动关闭

3. 系统 ID 点击后 truefalse 的区别

对于系统默认 ID(CUT/COPY 等),true 表示拦截系统行为 (你自己处理),false 表示让系统执行(正常复制粘贴)。

editMenuOptions 对比:bindSelectionMenu

特性 editMenuOptions bindSelectionMenu
适用对象 Web 内文字选中菜单 Web 内链接/图片长按菜单
菜单样式 跟随系统文字选中条 完全自定义 Popup/Sheet
支持预览 不支持 支持(PREVIEW_MENU
触发方式 选中文字时自动 长按指定元素类型

写在最后

editMenuOptions 是目前定制文字选中菜单最干净的方式,不需要拦截手势也不需要注入 JS。如果你的应用需要"选中文字后一键翻译/搜索/分享",这个 API 正好对味。

相关推荐
TrisighT3 小时前
ArkTS 组件传对象还是拆属性?我测了帧率,结果和直觉反着来
harmonyos·arkts
全栈若城19 小时前
HarmonyOS AppUtil 应用配置控制:颜色模式/灰度/字体/语言/键盘避让详解
华为·harmonyos·arkts·harmonyos6·键盘避让·字体缩放
JohnnyDeng942 天前
【鸿蒙】HarmonyOS 数据持久化:Preferences/KV Store/RelationalStore 选型指南
harmonyos·arkts·鸿蒙·数据持久化·arkui
JohnnyDeng942 天前
【鸿蒙】HarmonyOS 通知与后台任务:WorkScheduler 机制深度解析
harmonyos·arkts·鸿蒙·arkui·后台任务
奥特曼超人Dujinyang2 天前
鸿蒙小程序渲染一致性与性能治理终极架构
react·鸿蒙·dom·arkweb·阻塞 ui·失焦问题·scroll渲染
JohnnyDeng943 天前
【鸿蒙】ArkUI 列表性能优化:LazyForEach 与组件复用深度解析
性能优化·harmonyos·arkts·鸿蒙·arkui
芒鸽13 天前
HarmonyOS ArkTS 状态管理深度解析:@State、@Prop、@Link、@Provide/@Consume 实战指南
华为·harmonyos·arkts·状态管理
三声三视13 天前
Electron 窗口状态保存,我在鸿蒙 PC 上放弃了 electron-store
electron·arkts·鸿蒙
高心星16 天前
鸿蒙6.0应用开发——Web组件的生命周期
html·web组件·arkweb·鸿蒙6.0·harmonyos6.0