HarmonyOS NEXT应用开发之ArkWeb同层渲染

news2024/11/14 4:17:05

介绍

该方案展示了ArkWeb同层渲染:将系统原生组件直接渲染到前端H5页面上,原生组件不仅可以提供H5组件无法实现的一些功能,还能提升用户体验的流畅度

效果图预览

使用说明

  1. 进入页面即可看到同层渲染效果,Text,search,image都是原生组件。

实现思路

  1. 添加权限。
"ohos.permission.INTERNET"
  1. 创建控制器管理绑定的NodeContainer组件。
class SearchNodeController extends NodeController {
  private rootNode: BuilderNode<[Params]> | undefined | null = null;
  private embedId : string = "";
  private surfaceId : string = "";
  private renderType :NodeRenderType = NodeRenderType.RENDER_componentTypeDISPLAY;
  private componentWidth : number = 0;
  private componentHeight : number = 0;
  private componentType : string = "";

  setRenderOption(params : NodeControllerParams): void {
    this.surfaceId = params.surfaceId;
    this.renderType = params.renderType;
    this.embedId = params.embedId;
    this.componentWidth = params.width;
    this.componentHeight = params.height;
    this.componentType = params.type;
  }
  /**
   * 在对应NodeContainer创建的时候调用、或者通过rebuild方法调用刷新
   */
  makeNode(uiContext: UIContext): FrameNode | null{
    this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId, type: this.renderType});
    if (this.componentType === 'native/component') {
      this.rootNode.build(wrapBuilder(searchBuilder), { width : this.componentWidth, height : this.componentHeight});
    } else {
    }
    // 返回FrameNode节点
    return this.rootNode.getFrameNode();
  }
  /**
   * 设置BuilderNode节点
   */
  setBuilderNode(rootNode: BuilderNode<Params[]> | null): void{
    this.rootNode = rootNode;
  }
  /**
   * 获取BuilderNode节点
   */
  getBuilderNode(): BuilderNode<[Params]> | undefined | null{
    return this.rootNode;
  }
  /**
   * 更新BuilderNode节点
   */
  updateNode(arg: Object): void {
    this.rootNode?.update(arg);
  }
  /**
   * 获取EmbedId
   */
  getEmbedId() : string {
    return this.embedId;
  }
  /**
   * 将触摸事件派发到rootNode创建出的FrameNode上
   */
  postEvent(event: TouchEvent | undefined) : boolean {
    return this.rootNode?.postTouchEvent(event) as boolean;
  }
}
  1. 添加同层渲染的组件。
@Component
struct SearchComponent {
@Prop params: Params;
controller: SearchController = new SearchController();

build() {
  Column() {
    Column({ space: MARGIN_VERTICAL }) {
      Text($r('app.string.headline')).fontSize($r('app.string.ohos_id_text_size_body1'))
      Text($r('app.string.illustrate')).fontSize($r('app.string.ohos_id_text_size_body1'))
    }
    // 原生Text组件
    Text($r('app.string.mall')).fontSize($r('app.string.ohos_id_text_size_body1'))
    // 原生Search组件
    Search({ placeholder: 'Type to search...', controller: this.controller })
      .searchButton(SEARCH_BUTTON)
    // 原生Grid组件,Grid中包含Image和Text
    Grid() {
      // 性能知识点:此处数据量确定且数量较少,使用了ForEach,在数据量多的情况下,推荐使用LazyForeEach
      ForEach(PRODUCT_DATA, (item: ProductDataModel, index: number) => {
        GridItem() {
          Column({ space: MARGIN_VERTICAL }) {
            Image(item.uri).width($r('app.integer.image_size'))
            Row({ space: MARGIN_VERTICAL }) {
              Text(item.title).fontSize($r('app.string.ohos_id_text_size_body3'))
              Text(item.price).fontSize($r('app.string.ohos_id_text_size_body3'))
            }
          }
        }
      })
    }
    .columnsTemplate('1fr 1fr') // 2列
    .rowsTemplate('1fr 1fr ') // 2行
    .rowsGap($r('app.string.ohos_id_elements_margin_vertical_m')) // 行间距
    .columnsGap($r('app.string.ohos_id_elements_margin_vertical_m')) // 列间距
   }
 }
}
  1. embed标签可以在H5页面中嵌入任何类型的内容,在H5界面上通过embed标签标识同层元素,应用侧会将原生组件渲染到H5页面embed标签所在位置。
<div>
    <div id="bodyId">
        <!-- 在H5界面上通过embed标签标识同层元素,在应用侧将原生组件渲染到H5页面embed标签所在位置-->
        <embed id="nativeSearch" type = "native/component" width="100%" height="100%" src="view"/>
    </div>
</div>
  1. 通过WebView的enableNativeEmbedMode()控制同层渲染开关,通过onNativeEmbedLifecycleChange获取embed标签的生命周期变化数据。
build(){
  Column() {
    Stack() {
      // 性能知识点:此处componentId项确定且数量较少,使用了ForEach,在数据量多的情况下,推荐使用LazyForeEach
      ForEach(this.componentIdArr, (componentId: string) => {
        NodeContainer(this.nodeControllerMap.get(componentId));
      }, (embedId: string) => embedId)
      // web组件加载本地test.html页面
      Web({ src: $rawfile("view.html"), controller: this.browserTabController })
        .backgroundColor($r('app.color.ohos_id_color_sub_background'))
        // 不允许执行缩放
        .zoomAccess(false)
        // Todo: 知识点:通过enableNativeEmbedMode()配置同层渲染开关
        .enableNativeEmbedMode(true)
        // Todo: 知识点:通过onNativeEmbedLifecycleChange获取embed标签的生命周期变化数据
        .onNativeEmbedLifecycleChange((embed) => {
          // 获取web侧embed元素的id
          const componentId = embed.info?.id?.toString() as string
          if (embed.status === NativeEmbedStatus.CREATE) {
            // 创建节点控制器,设置参数并rebuild
            let nodeController = new SearchNodeController();
            // 外接纹理与WebView同层渲染
            nodeController.setRenderOption({surfaceId : embed.surfaceId as string, type : embed.info?.type as string, renderType : NodeRenderType.RENDER_componentTypeTEXTURE, embedId : embed.embedId as string, width : px2vp(embed.info?.width), height : px2vp(embed.info?.height)});
            nodeController.rebuild();
            // 根据web传入的embed的id属性作为key,将nodeController存入map
            this.nodeControllerMap.set(componentId, nodeController);
            // 将web传入的embed的id属性存入@State状态数组变量中,用于动态创建nodeContainer节点容器,需要将push动作放在set之后
            this.componentIdArr.push(componentId);
          } else if (embed.status === NativeEmbedStatus.UPDATE) {
            let nodeController = this.nodeControllerMap.get(componentId);
            nodeController?.updateNode({text: 'update', width: px2vp(embed.info?.width), height: px2vp(embed.info?.height)} as ESObject);
            nodeController?.rebuild();
          } else {
            let nodeController = this.nodeControllerMap.get(componentId);
            nodeController?.setBuilderNode(null);
            nodeController?.rebuild();
          }
        })// 获取同层渲染组件触摸事件信息
        .onNativeEmbedGestureEvent((touch) => {
          this.componentIdArr.forEach((componentId: string) => {
            let nodeController = this.nodeControllerMap.get(componentId);
            if (nodeController?.getEmbedId() === touch.embedId) {
              nodeController?.postEvent(touch.touchEvent);
            }
          })
        })
    }
  }
}
  1. h5侧通过id名获取embed标签信息,并通过embed标签添加同层渲染界面的touch监听事件;应用侧添加onNativeEmbedGestureEvent回调使得手指触摸到embed标签时能获取到触摸事件信息。
let nativeEmbed = {
  // 通过id名获取embed标签
  nativeSearch : document.getElementById('nativeSearch'),
  // 事件
  events:{},
  // 初始化
  init:function(){
    let self = this;
    // 添加touch的监听事件
    self.nativeSearch.addEventListener('touchstart', self.events, false);
  }
};
nativeEmbed.init();

Web({ src: $rawfile("view.html"), controller: this.browserTabController })
  // 获取同层渲染组件触摸事件信息
  .onNativeEmbedGestureEvent((touch) => {
    this.componentIdArr.forEach((componentId: string) => {
      let nodeController = this.nodeControllerMap.get(componentId);
      if (nodeController?.getEmbedId() === touch.embedId) {
        nodeController?.postEvent(touch.touchEvent);
      }
    })
  })

高性能知识点

ArkWeb同层渲染原生组件,原生组件不仅可以提供H5组件无法实现的一些功能,还能提升用户体验的流畅度;同层渲染节点上下树,实现节点复用,节省节点重复开销。

工程结构&模块类型

nativeembed                            // har类型
|---mock
|   |---GoodsMock.ets                  // 数据源
|---model
|   |---GoodsModel.ets                 // 数据类
|---view
|   |---NativeEmbedView.ets            // 视图层

模块依赖

本实例依赖common模块来实现资源的调用。 依赖动态路由模块来实现页面的动态加载。

参考资料

  1. Web
  2. BuilderNode
  3. NodeController
  4. ArkWeb(方舟Web)

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1542863.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

-bash: ./1.sh: /bin/bash^M: bad interpreter: No such file or directory解决方法

1、执行脚本 ./1.sh时报如下错误 -bash: ./1.sh: /bin/bash^M: bad interpreter: No such file or directory 2、在Windows编辑的脚本导入Linux系统中&#xff0c;执行报错问题 yum install -y dos2unix 3、或者本地安装 rpm -ivh /mnt/Packages/dos...... 4、然…

【战略前沿】丹麦正在建造一台英伟达人工智能超级计算机

【原文】Denmark is building an Nvidia AI supercomputer 【作者】Linnea Ahlgren 它将于今年上线&#xff0c;并以新的量子计算软件为特色。 过去一年最大的赢家——芯片制造商英伟达&#xff08;Nvidia&#xff09;和制药制造商诺和诺德&#xff08;Novo Nordisk&#xff0…

MCGS学习——用户管理

用户管理介绍 用户管理主要是为了实现触摸屏的安全操作&#xff0c;工业过程控制中&#xff0c;应该尽量避免由于人为的误操作所引发的故障或事故&#xff0c;而某些失误带来的后果是致命的&#xff1b;通过用户管理严格限制各类操作的权限&#xff0c;使不具备操作资格的人员…

LeetCode刷题日志-153.寻找旋转排序数组中的最小值

思路&#xff1a;总所周知二分的逻辑非常简单&#xff0c;难点在边界处理。这道题我说说自己的理解&#xff0c; 首先二分的根本是有序&#xff0c;只要有序就能二分&#xff0c;哪怕是部分有序&#xff08;这个是重点&#xff01;&#xff01;&#xff09; 我们先搞清楚题目中…

MyBatis:查询与连接池

一、查询 1、多表查询 尽量避免使用多表查询&#xff0c;尤其是对性能要求较高的项目。因为多表查询必然会导致性能变低。 例如&#xff1a;select *from ta运行需要10ms&#xff0c;select *from tb 运行也需要10s。但是&#xff0c;select *from ta left join tb on ta.xx…

【Web APIs】DOM节点

目录 1.节点操作 1.1DOM节点 1.2查找节点 1.2.1父节点查找 1.2.2子节点查找 1.2.3兄弟节点查找 1.3增加节点 1.4克隆节点 1.5删除节点 2.时间对象 2.1实例化 2.2时间对象方法 2.3时间戳 3.重绘和回流 1.节点操作 1.1DOM节点 DOM节点&#xff1a;DOM树中的每一个…

计算机网络:物理层中的数字传输系统全景概览解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

windows一键快速安装python方法

正常我们安装python的时候&#xff0c;需要先去下载python压缩包&#xff0c;然后再一步步安装&#xff0c;今天发现一个windows10下&#xff0c;一键安装python的方法&#xff1b; 电脑环境&#xff1a;windows10以上 安装方法&#xff1a; 0&#xff1a;在应用商店搜索pyt…

nodejs+vue反诈科普平台的设计与实现pythonflask-django-php

相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低反诈科普平台的运营人员成本&#xff0c;实现了反诈科普平台的标准化、制度化、程序化的管理&#xff0c;有效地防止了反诈科普平台的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够…

flask_Restful数据解析参数设置

add_argument 方法参数详解 add_argument方法可以指定这个字段的名字&#xff0c;这个字段的数据类 型等&#xff0c;验证错误提示信息等&#xff0c;具体如下&#xff1a; default&#xff1a;默认值&#xff0c;如果这个参数没有值&#xff0c;那么将使用这个参数 指定的默认…

防外破警示灯:高压线“守护神”,照亮安全之路

近年来&#xff0c;随着城市施工建设项目不断增多&#xff0c;大型施工机械在输电通道内活动越来越频繁&#xff0c;线路外破隐患点大幅增多。一旦施工机械在作业过程中碰触到高压线&#xff0c;将会造成线路外破事故&#xff0c;严重威胁输电线路和施工人员的安全。 哪些境况下…

STM32之HAL开发——HAL库框架介绍

HAL库外设设计思想 HAL库借鉴面向对象的设计思想&#xff0c;将外设驱动封装为对象。 HAL库使用主线 HAL使用的主要用在俩个地方&#xff0c;无外乎外设初始化以及外设的使用。想用好这两个功能&#xff0c;我们首先得对外设的封装有一定的了解。 句柄结构体 xx_HandleTypeDef…

二. CUDA编程入门-使用CUDA进行矩阵乘法的加速

目录 前言0. 简述1. 初步计算 MatMul1.1 执行一下我们的第三个CUDA程序1.2 host端与device端的数据传输1.3 CUDA Core的矩阵乘法计算1.4 代码分析 2. CUDA中的error handler2.1 为什么需要有error handler 3. 获取GPU信息3.1 执行一下我们的第五个CUDA程序3.2 为什么要注意硬件…

3月23日笔记

广播域与泛洪范围是相同的 广播&#xff1a;在同一个泛洪范围内&#xff0c;强迫交换机泛洪&#xff08;主动&#xff09; 泛洪&#xff08;被动&#xff09; ARP的工作原理&#xff1a;ARP先通过广播发送请求包&#xff0c;所有收到该广播包的设备都会将其中的源IP和源MAC相…

Node.js新手必备:超实用命令行入门教程

1.安装Node.js和npm 首先&#xff0c;我们需要下载并安装Node.js&#xff0c;它自带了npm&#xff08;Node Package Manager&#xff09;。安装完成后&#xff0c;在命令行输入&#xff1a; node -v npm -v 这两个命令分别显示已安装的Node.js和npm版本&#xff0c;确认安装成…

LeetCode 热题 HOT 100(P21~P30)

系列文章&#xff1a; LeetCode 热题 HOT 100(P1~P10)-CSDN博客 LeetCode 热题 HOT 100(P11~P20)-CSDN博客 LeetCode 热题 HOT 100(P21~P30)-CSDN博客 LC48rotate_image . - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给定一个 n n 的二维矩阵 matrix 表…

【电路笔记】-场效应管(FET)电流源

场效应管(FET)电流源 文章目录 场效应管(FET)电流源1、概述2、偏置结 FET2.1 N沟道JFET偏置2.2 N沟道JFET输出特性3、JFET 作为恒流源4、JFET 零电压偏置5、JFET 负电压偏置6、FET 恒流源示例17、JFET电流源8、FET 恒流源示例29、FET 恒流源示例310、总结FET 恒流源使用 JFET 和…

SpringBoot3集成PostgreSQL

标签&#xff1a;PostgreSQL.Druid.Mybatis.Plus&#xff1b; 一、简介 PostgreSQL是一个功能强大的开源数据库系统&#xff0c;具有可靠性、稳定性、数据一致性等特点&#xff0c;且可以运行在所有主流操作系统上&#xff0c;包括Linux、Unix、Windows等。 通过官方文档可以…

学习刷题-13

3.23 hw机试【二叉树】 剑指offer32 剑指 offer32&#xff08;一、二、三&#xff09;_剑指offer 32-CSDN博客 从上到下打印二叉树I 一棵圣诞树记作根节点为 root 的二叉树&#xff0c;节点值为该位置装饰彩灯的颜色编号。请按照从 左 到 右 的顺序返回每一层彩灯编号。 输…

WiFi已连接却不可上网是什么原因?

很多使用wifi上网的用户都遇到过这样的问题,就是电脑已经连接了wifi,但就是上不了网。着到底是怎么回事呢?今天,极客狗带大家一起来找找WiFi已连接却不可上网是什么原因,并给出对应的解决方。 原因分析: 可能是ip地址冲突所导致,也有可能是宽带出先故障,不妨试试下面的…