HarmonyOS ArkWeb 系列之文本选中菜单定制:editMenuOptions 深度解析
文章目录
- 和 onContextMenuShow 有什么区别?
- 核心概念:TextMenuItem 和 TextMenuItemId
- 文本菜单定制流程
- 完整示例代码
- `textRange` 是什么
- 系统内置 TextMenuItemId 一览
- 几个注意点
- 和 `editMenuOptions` 对比:bindSelectionMenu
- 写在最后
选中网页里的文字,上面弹出一排小按钮(复制、剪切、粘贴……)——这排按钮叫"文本选中菜单"。
editMenuOptions让你完全控制这里出现什么。
和 onContextMenuShow 有什么区别?
别搞混:
onContextMenuShow:长按触发,适合图片、链接的右键菜单editMenuOptions:选中文字后弹出的那一排操作按钮
两个是不同场景,API 也完全不同。
核心概念:TextMenuItem 和 TextMenuItemId
大白话解释:
TextMenuItem就是菜单里的一个按钮,有三个属性:
content:显示的文字或图标资源id:这个按钮的唯一标识,用来区分是哪个按钮被点了icon(可选):按钮旁边的小图标
TextMenuItemId是系统内置的 ID 枚举,用TextMenuItemId.CUT、TextMenuItemId.COPY这样的方式引用系统默认按钮。自定义按钮用TextMenuItemId.of('你的自定义ID')创建。
文本菜单定制流程
完整示例代码
import{webview}from'@kit.ArkWeb';@Entry@Componentstruct WebTextMenuDemo{controller:webview.WebviewController=newwebview.WebviewController();// onCreateMenu:决定菜单里放哪些按钮// 参数 menuItems 是系统默认的全部菜单项数组onCreateMenu(menuItems:Array<TextMenuItem>):Array<TextMenuItem>{// 第一步:从系统菜单里只保留我们想要的letitems=menuItems.filter((menuItem)=>{return(menuItem.id.equals(TextMenuItemId.CUT)||menuItem.id.equals(TextMenuItemId.COPY)||menuItem.id.equals(TextMenuItemId.PASTE));});// 第二步:添加自定义菜单项letshareItem:TextMenuItem={content:'分享',id:TextMenuItemId.of('action_share'),icon:$r('app.media.share_icon')// 替换为实际图标资源};lettranslateItem:TextMenuItem={content:'翻译',id:TextMenuItemId.of('action_translate'),icon:$r('app.media.translate_icon')};// 在末尾追加自定义项items.push(shareItem);items.push(translateItem);returnitems;}// onMenuItemClick:某个菜单项被点击时的回调// 返回 true = 拦截(系统默认行为不执行)// 返回 false = 不拦截(系统默认行为照常执行)onMenuItemClick(menuItem:TextMenuItem,textRange:TextRange):boolean{if(menuItem.id.equals(TextMenuItemId.CUT)){// 剪切:先做自己的逻辑,再拦截系统行为console.info('用户剪切了文字,范围:',textRange.start,'-',textRange.end);returnfalse;// false = 系统剪切照常执行}if(menuItem.id.equals(TextMenuItemId.COPY)){console.info('用户复制了文字');returnfalse;// 不拦截,让系统正常复制}if(menuItem.id.equals(TextMenuItemId.of('action_share'))){// 自定义分享逻辑console.info('用户点了分享');// ... 调用分享面板returntrue;// true = 菜单保持不关闭(适合需要二级操作的情况)}if(menuItem.id.equals(TextMenuItemId.of('action_translate'))){console.info('用户点了翻译');// ... 调用翻译服务returntrue;}returnfalse;// 默认不拦截}// 把两个回调封装成 EditMenuOptions 对象@StateeditMenuOptions: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包含用户选中的文字范围:
interfaceTextRange{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 正好对味。
