HarmonyOS NEXT 使用Web自定义长按菜单案例

介绍

本示例介绍了给Webview页面中可点击元素(超链接/图片)绑定长按/鼠标右击时的自定义菜单的方案。

效果预览图

使用说明

长按Web页面中的图片或者链接元素,弹出自定义的Menu菜单,创建自定义的操作,如复制图片、使用浏览器打开链接、复制链接等。

实现思路

  1. 创建Web组件,导入示例HTML文件,绑定弹出菜单组件。
Web({ src: $rawfile("index.html"), controller: this.controller })
  .bindPopup(this.showMenu,
    {
      builder: this.MenuBuilder(),
      enableArrow: false,
      placement: Placement.LeftTop,
      mask: false,
      onStateChange: (e) => {
        if (!e.isVisible) {
          this.showMenu = false;
          this.result!.closeContextMenu();
        }
      }
    })
  1. 调用Web组件的onContextMenuShow函数,获取当前页面元素弹窗菜单的信息,如位置信息、当前链接、以及是否存在图片等媒体元素、获取事件来源等。同时也获取弹出菜单的响应事件,用于处理前面获取到的菜单信息,如复制图片、全选、剪切、关闭菜单等。
// TODO: 知识点: 长按或者鼠标右键触发该事件,当前只对图片、链接有效。
.onContextMenuShow((event) => {
  if (event) {
    this.result = event.result;
    this.param = event.param;
    logger.info(TAG, "x coord = " + event.param.x());
    logger.info(TAG, "y coord = " + event.param.y());
    logger.info(TAG, "link url = " + event.param.getLinkUrl())
    this.linkUrl = event.param.getLinkUrl();
    this.inputType = this.param.getInputFieldType();
  }
  logger.info(TAG, TAG, `x: ${this.offsetX}, y: ${this.offsetY}`);
  this.showMenu = true;
  return true;
})
  1. 创建自定义菜单。在onContextMenuShow事件中能够获取触发菜单元素的信息和事件,根据这些内容动态创建自定义的弹出菜单。
Menu() {
  // 如果元素存在图片
  if (this.param?.existsImageContents()) {
    MenuItem({
      content: $r('app.string.copy_image'),
    })
      .onClick(() => {
        this.result?.copyImage();
        this.showMenu = false;
      })
  }
  // 如果元素可剪切
  if (this.param?.getEditStateFlags() === ContextMenuEditStateFlags.CAN_CUT) {
    MenuItem({
      content: $r('app.string.cut'),
    })
      .onClick(() => {
        this.result?.cut();
        this.showMenu = false;
      })
  }
  // 如果元素可拷贝
  if (this.param?.getEditStateFlags() === ContextMenuEditStateFlags.CAN_PASTE) {
    MenuItem({
      content: $r('app.string.copy'),
    })
      .onClick(() => {
        this.result?.copy();
        this.showMenu = false;
      })
  }
  // 如果元素可粘贴
  if (this.param?.getEditStateFlags() === ContextMenuEditStateFlags.CAN_PASTE) {
    MenuItem({
      content: $r('app.string.paste'),
    })
      .onClick(() => {
        this.result?.paste();
        this.showMenu = false;
      })
  }
  // 如果元素可全选
  if (this.param?.getEditStateFlags() === ContextMenuEditStateFlags.CAN_PASTE) {
    MenuItem({
      content: $r('app.string.select_all'),
    })
      .onClick(() => {
        this.result?.selectAll();
        this.showMenu = false;
      })
  }
  // 如果元素为链接
  if (this.linkUrl) {
    // 浏览器打开链接
    MenuItem({
      content: $r('app.string.open_link'),
    })
      .onClick(() => {
        let wantInfo: Want = {
          action: 'ohos.want.action.viewData',
          entities: ['entity.system.browsable'],
          uri: this.linkUrl
        };
        this.context.startAbility(wantInfo).then(() => {
          logger.info(TAG, 'startAbility succeed');
        }).catch((err: BusinessError) => {
          logger.error(TAG, `startAbility failed, code is ${err.code}, message is ${err.message}`);
          return;
        });
        this.showMenu = false;
      })
    // 复制链接
    MenuItem({
      content: $r('app.string.copy_link'),
    })
      .onClick(() => {
        let pasteData = pasteboard.createData('text/plain', this.linkUrl);
        pasteboard.getSystemPasteboard().setData(pasteData, (error) => {
          if (error) {
            logger.error(TAG, 'Failed to set PasteData. Cause: ' + error.message);
            return;
          }
          logger.info(TAG, 'Succeeded in setting PasteData.');
        });
        this.showMenu = false;
      })
  }
  // 判断是否输入框
  if (this.inputType != ContextMenuInputFieldType.None) {
    MenuItem({
      content: $r('app.string.input_field'),
    })
      .onClick(() => {
        this.showMenu = false;
      })
  }
}

因为不同元素触发的弹窗宽高尺寸不一样,还需要根据手指按压位置和弹窗尺寸选择弹窗显示的位置。

let offset: Position = { x: 0, y: 0};
if (this.pressPosX <= this.webWidth / 2) {
  offset.x = -(this.webWidth / 2 - this.pressPosX) + popupWidth / 2 + FINGER_OFFSET_X;
} else {
  offset.x = -(this.webWidth / 2 - this.pressPosX) - popupWidth / 2 - FINGER_OFFSET_X;
}
if (this.pressPosY <= this.webHeight / 2) {
  offset.y = -(this.webHeight / 2 - this.pressPosY) + popupHeight / 2 + FINGER_OFFSET_Y;
} else {
  offset.y = (this.pressPosY - this.webHeight / 2) - popupHeight / 2 - FINGER_OFFSET_Y;
}
logger.debug(TAG, `popup offset: ${offset.x}, ${offset.y}`);
return offset;
}

高性能知识点

  • 本案例使用了Webview控制器的 initializeWebEngine 接口提前加载Web引擎的动态库文件,从而提前进行Web组件动态库的加载和Web内核主进程的初始化,最终以提高启动性能,减少白屏时间。
  • 本案例使用了系统高频回调事件 onAreaChange ,应避免在该回调中调用冗余和耗时操作。

工程结构&模块类型

webcustompressmenu      // HAR类型
  ├─mainpage
  │ └─MainPage.ets      // ArkTS页面
  ├─rawfile
  │ └─index.html        // HTML页面
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.1024c.cn/archives/21294,转载请注明出处。
1

评论0

显示验证码
没有账号?注册  忘记密码?