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.CUT、TextMenuItemId.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. 自定义项点击后 true 和 false 的区别

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

3. 系统 ID 点击后 true 和 false 的区别

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

和 editMenuOptions 对比:bindSelectionMenu

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

写在最后

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

相关推荐
雨雨雨雨雨别下啦1 小时前
【OpenHarmony北向开发】ArkTS基础教学
typescript·arkts·openharmonys
MardaWang6 天前
当滚动逃离了框架 ——HarmonyOS Web 与原生混排滚动的冲突本质与解法
harmonyos·arkts·鸿蒙·deveco studio
1099054189 天前
ArkTS语言的数据类型之Array类型
arkts
贾伟康12 天前
【HarmonyOS 7新能力|066】弱网直播优化实战:从网络感知到码率、缓冲与恢复
音视频·harmonyos·arkts·网络优化·弱网直播
贾伟康14 天前
【HarmonyOS 7新能力|065】QUIC长连接实战:弱网推送、会话恢复与连接治理
harmonyos·arkts·quic·长连接·弱网优化
贾伟康14 天前
【HarmonyOS 7新能力|067】LTPO可变帧率实战:让动画流畅而静态页面省电
harmonyos·arkts·低功耗·ltpo·可变帧率
看谷秀14 天前
arkts-12 鸿蒙生态/卡片
前端·arkts
行者-全栈开发14 天前
华为云码道 CodeArts 实测:让 AI 独立开发一个鸿蒙原生专注计时应用「刻循」
harmonyos·arkts·鸿蒙·ai 编程·华为云码道·codearts 代码智能体·专注计时
威哥爱编程15 天前
HarmonyOS 7 自由多窗实战:supportWindowMode + 断点布局,大屏多任务主动接管
harmonyos·arkts