鸿蒙HarmonyOS开发实战往期必看文章:(持续更新......)
HarmonyOS NEXT应用开发性能实践总结(持续更新......)
HarmonyOS NEXT应用开发案例实践总结合集(持续更新......)
一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!
最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)
介绍
本示例介绍了给Webview页面中可点击元素(超链接/图片)绑定长按/鼠标右击时的自定义菜单的方案。
效果预览图
使用说明
长按Web页面中的图片或者链接元素,弹出自定义的Menu菜单,创建自定义的操作,如复制图片、使用浏览器打开链接、复制链接等。
实现思路
- 创建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();
- }
- }
- })
- 调用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;
- })
- 创建自定义菜单。在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页面
模块依赖
最后
小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线图、学习视频、文档用来跟着学习是非常有必要的。
如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员
鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~
这份鸿蒙(HarmonyOS NEXT)包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
鸿蒙(HarmonyOS NEXT)最新学习路线
该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案
路线图适合人群:
IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术
2.视频学习教程+学习PDF文档
HarmonyOS Next 最新全套视频教程 全球开发者的开源社区,开源代码
纯血版鸿蒙全套学习文档(面试、文档、全套视频等) 全球开发者的开源社区,开源代码
《鸿蒙大厂面试真题》GitCode - 全球开发者的开源社区,开源代码
总结
参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线



评论记录:
回复评论: