欢迎光临
我们一直在努力

HarmonyOS ArkWeb 系列之 右键菜单完全自定义:onContextMenuShow 用法详解

文章目录

      • 先搞清楚"右键菜单"是什么
      • 流程图:右键菜单触发全流程
      • 最简实现:把系统菜单换成自己的
      • 几个容易踩的坑
      • `event.param` 都能拿到什么
      • `result` 能执行哪些操作
      • 写在最后

长按网页里的链接或图片,系统弹出一个菜单——这个菜单能不能换成我们自己设计的样式?答案是可以。
onContextMenuShow 就是干这个的。

先搞清楚"右键菜单"是什么

在手机上,长按网页中的文字、图片、链接,会弹出一个操作菜单(复制、粘贴、保存图片……)。在桌面端就是鼠标右键菜单。

ArkWeb 的 onContextMenuShow 回调在这个时机触发,给你两个关键参数:

  • event.param:当前长按位置的信息(坐标、链接地址、图片地址……)
  • event.result:操作句柄,调它的方法可以执行复制/粘贴/关闭菜单等系统行为

返回 true 表示"我自己处理,系统别弹了";返回 false 表示"用系统默认菜单就行"。

流程图:右键菜单触发全流程

最简实现:把系统菜单换成自己的

import { webview } from '@kit.ArkWeb';
import { pasteboard } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebContextMenuDemo {
controller: webview.WebviewController = new webview.WebviewController();
// 保存菜单操作句柄,点菜单项时调用
private result: WebContextMenuResult | undefined = undefined;
@State linkUrl: string = '';
@State showMenu: boolean = false;
@State offsetY: number = 0;
uiContext: UIContext = this.getUIContext();

// 用 @Builder 声明自定义菜单内容
@Builder
MenuBuilder() {
Menu() {
MenuItem({ content: '复制图片' })
.width(200).height(50)
.onClick(() => {
this.result?.copyImage(); // 调系统复制图片
this.showMenu = false;
})
MenuItem({ content: '剪切' })
.width(200).height(50)
.onClick(() => {
this.result?.cut();
this.showMenu = false;
})
MenuItem({ content: '复制' })
.width(200).height(50)
.onClick(() => {
this.result?.copy();
this.showMenu = false;
})
MenuItem({ content: '粘贴' })
.width(200).height(50)
.onClick(() => {
this.result?.paste();
this.showMenu = false;
})
MenuItem({ content: '复制链接' })
.width(200).height(50)
.onClick(() => {
// 手动写入剪贴板
let pasteData = pasteboard.createData(
pasteboard.MIMETYPE_TEXT_PLAIN, this.linkUrl
);
pasteboard.getSystemPasteboard().setData(pasteData, (error) => {
if (error) { return; }
});
this.showMenu = false;
})
MenuItem({ content: '全选' })
.width(200).height(50)
.onClick(() => {
this.result?.selectAll();
this.showMenu = false;
})
}
.width(150)
.height(300)
}

build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.onContextMenuShow((event) => {
if (event) {
// 保存句柄和链接地址
this.result = event.result;
this.linkUrl = event.param.getLinkUrl();
// 根据长按 Y 坐标定位菜单弹出位置
this.offsetY = Math.max(
this.uiContext.px2vp(event.param.y() ?? 0) 0, 0
);
}
this.showMenu = true;
return true; // 关键:返回 true 阻止系统菜单
})
.bindPopup(this.showMenu, {
builder: this.MenuBuilder(),
enableArrow: false,
placement: Placement.LeftTop,
offset: { x: 0, y: this.offsetY },
mask: false,
onStateChange: (e) => {
if (!e.isVisible) {
this.showMenu = false;
this.result?.closeContextMenu(); // 菜单消失时通知内核关闭
}
}
})
}
}
}

几个容易踩的坑

坑1:忘记调 closeContextMenu()

菜单消失后如果不调这个,Web 内核状态不同步,下次再长按可能出问题。一定要在 onStateChange 里菜单不可见时调一次。

坑2:event.param.y() 返回的是像素值

屏幕坐标是 px,ArkUI 布局用的是 vp,需要用 this.getUIContext().px2vp() 转换,否则菜单位置会乱。

坑3:result 保存时机

result 必须在 onContextMenuShow 回调里保存,不能用成员变量直接操作,因为每次长按都是一个新的 result 对象。

event.param 都能拿到什么

方法说明
x() / y() 长按位置坐标(px)
getLinkUrl() 链接地址
getUnfilteredLinkUrl() 原始链接(未过滤)
getSourceUrl() 图片/媒体资源地址
existsImageContents() 当前位置是否有图片
getPreviewWidth() / getPreviewHeight() 图片预览尺寸(px)

result 能执行哪些操作

方法说明
copy() 复制选中内容
cut() 剪切选中内容
paste() 粘贴
copyImage() 复制图片
selectAll() 全选
closeContextMenu() 关闭上下文菜单

写在最后

onContextMenuShow 的设计很灵活,你既可以完全替换菜单,也可以只监听事件做一些统计、日志记录,然后返回 false 让系统菜单照常弹出。根据实际需求选择就行,不必过度封装。

赞(0)
未经允许不得转载:171主机测评 » HarmonyOS ArkWeb 系列之 右键菜单完全自定义:onContextMenuShow 用法详解
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址