欢迎光临
我们一直在努力

HarmonyOS ArkWeb 系列给 Web 里的链接和图片加专属长按菜单 bindSelectionMenu

文章目录

      • 和 onContextMenuShow 的差别
      • 核心参数说明
      • 流程图:bindSelectionMenu 工作机制
      • 完整示例:链接菜单 + 图片菜单分开绑定
      • 高级用法:禁用长按手势
      • 和 `SelectionMenuOptionsExt` 配合:加菜单出现/消失动画
      • 一个常见误区
      • 写在最后

你有没有遇到这种需求:长按网页里的链接弹出"在新窗口打开/复制链接/收藏",长按图片弹出"保存/分享/设为壁纸"?这两种不同元素的长按菜单要分开定制。bindSelectionMenu 正是为这个场景设计的。

和 onContextMenuShow 的差别

老实说刚接触这块 API 时我把这两个搞混过。区别如下:

  • onContextMenuShow:全局的长按菜单拦截,不区分元素类型,一刀切替换
  • bindSelectionMenu:按元素类型分别绑定,链接绑一套,图片绑另一套,互不干扰

选哪个取决于你要不要区分对待不同元素。如果链接和图片的菜单不一样,用 bindSelectionMenu。

核心参数说明

// 方法签名
.bindSelectionMenu(
elementType: WebElementType, // 要绑定到哪种元素
menuBuilder: CustomBuilder, // 菜单内容(@Builder)
responseType: WebResponseType, // 触发方式
options?: SelectionMenuOptionsExt // 可选配置(预览、回调等)
)

WebElementType:

  • WebElementType.LINK → 链接
  • WebElementType.IMAGE → 图片

WebResponseType:

  • WebResponseType.LONG_PRESS → 长按触发
  • WebResponseType.RIGHT_CLICK → 右键触发(折叠屏/平板)

流程图:bindSelectionMenu 工作机制

完整示例:链接菜单 + 图片菜单分开绑定

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

@Entry
@Component
struct WebBindSelectionMenuDemo {
controller: webview.WebviewController = new webview.WebviewController();
private result: WebContextMenuResult | undefined = undefined;

// 当前长按的链接地址和图片地址
@State linkURL: string = '';
@State imageURL: string | Resource | undefined = undefined;
@State previewWidth: number = 300;
@State previewHeight: number = 200;

uiContext: UIContext = this.getUIContext();

// ========== 链接菜单 ==========
@Builder
LinkMenuBuilder() {
Menu() {
MenuItem({ content: '复制链接' })
.onClick(() => {
const data = pasteboard.createData(
pasteboard.MIMETYPE_TEXT_PLAIN, this.linkURL
);
pasteboard.getSystemPasteboard().setData(data);
})
MenuItem({ content: '在当前页打开' })
.onClick(() => {
this.controller.loadUrl(this.linkURL);
})
}
}

// ========== 图片菜单 ==========
@Builder
ImageMenuBuilder() {
Menu() {
MenuItem({ content: '复制图片' })
.onClick(() => {
this.result?.copyImage();
this.result?.closeContextMenu();
})
MenuItem({ content: '分享图片' })
.onClick(() => {
console.info('分享图片:', this.imageURL);
this.result?.closeContextMenu();
})
}
}

build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptAccess(true)
.fileAccess(true)
.onlineImageAccess(true)
.imageAccess(true)
.domStorageAccess(true)
// 绑定链接元素的长按菜单
.bindSelectionMenu(
WebElementType.LINK,
this.LinkMenuBuilder,
WebResponseType.LONG_PRESS,
{
onAppear: () => {
console.info('链接菜单出现');
},
onDisappear: () => {
this.result?.closeContextMenu();
}
}
)
// 绑定图片元素的长按菜单
.bindSelectionMenu(
WebElementType.IMAGE,
this.ImageMenuBuilder,
WebResponseType.LONG_PRESS,
{
onAppear: () => {
console.info('图片菜单出现');
},
onDisappear: () => {
this.result?.closeContextMenu();
}
}
)
// 配合 onContextMenuShow 保存 result 和 URL
.onContextMenuShow((event) => {
if (event) {
this.result = event.result;
this.linkURL = event.param.getLinkUrl();
this.previewWidth = this.uiContext.px2vp(event.param.getPreviewWidth());
this.previewHeight = this.uiContext.px2vp(event.param.getPreviewHeight());
const srcUrl = event.param.getSourceUrl();
if (srcUrl.startsWith('resource://rawfile/')) {
this.imageURL = $rawfile(srcUrl.substring(19));
} else {
this.imageURL = srcUrl;
}
return true;
}
return false;
})
}
}
}

高级用法:禁用长按手势

有时候你完全不想让用户长按选择文字,可以用 WebDisableLongPress 的方案——通过 JavaScript 注入禁用:

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

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

build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.onPageEnd(() => {
// 页面加载完毕后注入 JS,禁用长按选中
this.controller.runJavaScript(
`document.body.style.userSelect = 'none';
document.body.style.webkitUserSelect = 'none';
`

);
})
}
}
}

如果你想更细粒度,只禁止某个区域,把 document.body 换成对应的元素选择器即可。

和 SelectionMenuOptionsExt 配合:加菜单出现/消失动画

.bindSelectionMenu(
WebElementType.LINK,
this.LinkMenuBuilder,
WebResponseType.LONG_PRESS,
{
onAppear: () => {
// 菜单出现时,可以做一些 UI 联动
this.showOverlay = true;
},
onDisappear: () => {
this.showOverlay = false;
this.result?.closeContextMenu();
}
}
)

一个常见误区

bindSelectionMenu 和 onContextMenuShow 要配合使用,不是二选一。

  • bindSelectionMenu 控制的是菜单内容
  • onContextMenuShow 里你需要返回 true,同时可以在这里保存 result 和 URL 信息,供菜单里的按钮使用

如果 onContextMenuShow 返回 false,系统菜单会覆盖你的 bindSelectionMenu。

写在最后

bindSelectionMenu 在需要区分元素类型的场景下非常好用,链接菜单和图片菜单各自独立,代码也更清晰。配合下一篇的预览菜单(PREVIEW_MENU)食用效果更佳。

赞(0)
未经允许不得转载:171主机测评 » HarmonyOS ArkWeb 系列给 Web 里的链接和图片加专属长按菜单 bindSelectionMenu
分享到: 更多 (0)

评论 抢沙发

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