文章目录
- 和 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@Componentstruct WebBindSelectionMenuDemo{controller:webview.WebviewController=newwebview.WebviewController();privateresult:WebContextMenuResult|undefined=undefined;// 当前长按的链接地址和图片地址@StatelinkURL:string='';@StateimageURL:string|Resource|undefined=undefined;@StatepreviewWidth:number=300;@StatepreviewHeight:number=200;uiContext:UIContext=this.getUIContext();// ========== 链接菜单 ==========@BuilderLinkMenuBuilder(){Menu(){MenuItem({content:'复制链接'}).onClick(()=>{constdata=pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN,this.linkURL);pasteboard.getSystemPasteboard().setData(data);})MenuItem({content:'在当前页打开'}).onClick(()=>{this.controller.loadUrl(this.linkURL);})}}// ========== 图片菜单 ==========@BuilderImageMenuBuilder(){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());constsrcUrl=event.param.getSourceUrl();if(srcUrl.startsWith('resource://rawfile/')){this.imageURL=$rawfile(srcUrl.substring(19));}else{this.imageURL=srcUrl;}returntrue;}returnfalse;})}}}高级用法:禁用长按手势
有时候你完全不想让用户长按选择文字,可以用WebDisableLongPress的方案——通过 JavaScript 注入禁用:
import{webview}from'@kit.ArkWeb';@Entry@Componentstruct WebDisableLongPressDemo{controller:webview.WebviewController=newwebview.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)食用效果更佳。