首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

HarmonyOS鸿蒙开发实战(5.0)ArkWeb同层渲染

  • 25-03-03 06:42
  • 2644
  • 12249
blog.csdn.net

鸿蒙HarmonyOS开发实战往期必看文章:(持续更新......)

HarmonyOS NEXT应用开发性能实践总结(持续更新......)

HarmonyOS NEXT应用开发案例实践总结合集(持续更新......)

一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!

最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)


介绍

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

效果图预览

使用说明

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

实现思路

  1. 添加权限。源码参考module.json5
    "ohos.permission.INTERNET"
    
  2. 创建控制器管理绑定的NodeController。源码参考NativeEmbedView.ets
    1. class SearchNodeController extends NodeController {
    2. private rootNode: BuilderNode<[Params]> | undefined | null = null;
    3. private embedId: string = "";
    4. private surfaceId: string = "";
    5. private renderType: NodeRenderType = NodeRenderType.RENDER_componentTypeDISPLAY;
    6. private componentWidth: number = 0;
    7. private componentHeight: number = 0;
    8. private componentType: string = "";
    9. setRenderOption(params : NodeControllerParams): void {
    10. this.surfaceId = params.surfaceId;
    11. this.renderType = params.renderType;
    12. this.embedId = params.embedId;
    13. this.componentWidth = params.width;
    14. this.componentHeight = params.height;
    15. this.componentType = params.type;
    16. }
    17. /**
    18. * 在对应NodeContainer创建的时候调用、或者通过rebuild方法调用刷新
    19. */
    20. makeNode(uiContext: UIContext): FrameNode | null {
    21. this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId, type: this.renderType});
    22. if (this.componentType === 'native/component') {
    23. this.rootNode.build(wrapBuilder(searchBuilder), { width: this.componentWidth, height: this.componentHeight});
    24. } else {
    25. }
    26. // 返回FrameNode节点
    27. return this.rootNode.getFrameNode();
    28. }
    29. /**
    30. * 设置BuilderNode节点
    31. */
    32. setBuilderNode(rootNode: BuilderNode<Params[]> | null): void {
    33. this.rootNode = rootNode;
    34. }
    35. /**
    36. * 获取BuilderNode节点
    37. */
    38. getBuilderNode(): BuilderNode<[Params]> | undefined | null {
    39. return this.rootNode;
    40. }
    41. /**
    42. * 更新BuilderNode节点
    43. */
    44. updateNode(arg: Object): void {
    45. this.rootNode?.update(arg);
    46. }
    47. /**
    48. * 获取EmbedId
    49. */
    50. getEmbedId(): string {
    51. return this.embedId;
    52. }
    53. /**
    54. * 将触摸事件派发到rootNode创建出的FrameNode上
    55. */
    56. postEvent(event: TouchEvent | undefined): boolean {
    57. return this.rootNode?.postTouchEvent(event) as boolean;
    58. }
    59. }
  3. 添加同层渲染的组件。源码参考NativeEmbedView.ets
    1. @Component
    2. struct SearchComponent {
    3. @Prop params: Params;
    4. build() {
    5. Column({ space: MARGIN_VERTICAL }) {
    6. // 原生Text组件
    7. Text($r('app.string.mall')).fontSize($r('app.string.ohos_id_text_size_body1'))
    8. Row() {
    9. Image($r('app.media.search_icon'))
    10. .width($r('app.integer.search_icon_width'))
    11. .margin({ left: $r('app.integer.left_margin') })
    12. Text($r('app.string.search_text_placeholder'))
    13. .fontSize($r('app.string.ohos_id_text_size_body2'))
    14. .opacity(OPACITY)
    15. .fontColor($r('app.color.ohos_id_color_foreground'))
    16. .margin({ left: $r('app.integer.left_margin') })
    17. }
    18. // 原生Grid组件,Grid中包含Image和Text
    19. Grid() {
    20. // 性能知识点:此处数据量确定且数量较少,使用了ForEach,在数据量多的情况下,推荐使用LazyForeEach
    21. ForEach(PRODUCT_DATA, (item: ProductDataModel, index: number) => {
    22. GridItem() {
    23. Column({ space: MARGIN_VERTICAL }) {
    24. Image(item.uri).width($r('app.integer.image_size'))
    25. Row({ space: MARGIN_VERTICAL }) {
    26. Text(item.title).fontSize($r('app.string.ohos_id_text_size_body3'))
    27. Text(item.price).fontSize($r('app.string.ohos_id_text_size_body3'))
    28. }
    29. }
    30. }
    31. })
    32. }
    33. .columnsTemplate('1fr 1fr')
    34. .rowsTemplate('1fr 1fr 1fr')
    35. .rowsGap($r('app.string.ohos_id_elements_margin_vertical_m'))
    36. .columnsGap($r('app.string.ohos_id_elements_margin_vertical_m'))
    37. }
    38. }
    39. }
  4. embed标签可以在H5页面中嵌入任何类型的内容,在H5界面上通过embed标签标识同层元素,应用侧会将原生组件渲染到H5页面embed标签所在位置。源码参考view.html
    1. <div>
    2. <div id="bodyId">
    3. <!-- 在H5界面上通过embed标签标识同层元素,在应用侧将原生组件渲染到H5页面embed标签所在位置-->
    4. <embed id="nativeSearch" type = "native/component" width="100%" height="100%" src="view"/>
    5. </div>
    6. </div>
  5. 通过WebView的enableNativeEmbedMode()控制同层渲染开关,通过onNativeEmbedLifecycleChange获取embed标签的生命周期变化数据。源码参考NativeEmbedView.ets
    1. build(){
    2. Stack() {
    3. // 性能知识点:此处componentId项确定且数量较少,使用了ForEach,在数据量多的情况下,推荐使用LazyForeEach
    4. ForEach(this.componentIdArr, (componentId: string) => {
    5. NodeContainer(this.nodeControllerMap.get(componentId));
    6. }, (embedId: string) => embedId)
    7. // web组件加载本地test.html页面
    8. Web({ src: $rawfile("view.html"), controller: this.browserTabController })
    9. .backgroundColor($r('app.color.ohos_id_color_sub_background'))
    10. .zoomAccess(false) // 不允许执行缩放
    11. .enableNativeEmbedMode(true) // TODO: 知识点:通过enableNativeEmbedMode()配置同层渲染开关
    12. .onNativeEmbedLifecycleChange((embed) => { // TODO: 知识点:通过onNativeEmbedLifecycleChange获取embed标签的生命周期变化数据
    13. // 获取web侧embed元素的id
    14. const componentId = embed.info?.id?.toString() as string
    15. if (embed.status === NativeEmbedStatus.CREATE) {
    16. // 创建节点控制器,设置参数并rebuild
    17. let nodeController = new SearchNodeController();
    18. // 外接纹理与WebView同层渲染
    19. nodeController.setRenderOption({
    20. surfaceId: embed.surfaceId as string,
    21. type: embed.info?.type as string,
    22. renderType: NodeRenderType.RENDER_TYPE_TEXTURE,
    23. embedId: embed.embedId as string,
    24. width: px2vp(embed.info?.width),
    25. height: px2vp(embed.info?.height)
    26. });
    27. nodeController.rebuild();
    28. // 根据web传入的embed的id属性作为key,将nodeController存入map
    29. this.nodeControllerMap.set(componentId, nodeController);
    30. // 将web传入的embed的id属性存入@State状态数组变量中,用于动态创建nodeContainer节点容器,需要将push动作放在set之后
    31. this.componentIdArr.push(componentId);
    32. } else if (embed.status === NativeEmbedStatus.UPDATE) {
    33. let nodeController = this.nodeControllerMap.get(componentId);
    34. nodeController?.updateNode({
    35. text: 'update',
    36. width: px2vp(embed.info?.width),
    37. height: px2vp(embed.info?.height)
    38. } as ESObject);
    39. nodeController?.rebuild();
    40. } else {
    41. let nodeController = this.nodeControllerMap.get(componentId);
    42. nodeController?.setBuilderNode(null);
    43. nodeController?.rebuild();
    44. }
    45. })
    46. .onNativeEmbedGestureEvent((touch) => { // 获取同层渲染组件触摸事件信息
    47. this.componentIdArr.forEach((componentId: string) => {
    48. let nodeController = this.nodeControllerMap.get(componentId);
    49. if (nodeController?.getEmbedId() === touch.embedId) {
    50. nodeController?.postEvent(touch.touchEvent);
    51. }
    52. })
    53. })
    54. }
    55. }
  6. h5侧通过id名获取embed标签信息,并通过embed标签添加同层渲染界面的touch监听事件;应用侧添加onNativeEmbedGestureEvent回调使得手指触摸到embed标签时能获取到触摸事件信息。源码参考view.html和NativeEmbedView.ets
    1. let nativeEmbed = {
    2. // 通过id名获取embed标签
    3. nativeSearch : document.getElementById('nativeSearch'),
    4. // 事件
    5. events:{},
    6. // 初始化
    7. init:function(){
    8. let self = this;
    9. // 添加touch的监听事件
    10. self.nativeSearch.addEventListener('touchstart', self.events, false);
    11. }
    12. };
    13. nativeEmbed.init();
    1. Web({ src: $rawfile("view.html"), controller: this.browserTabController })
    2. // 获取同层渲染组件触摸事件信息
    3. .onNativeEmbedGestureEvent((touch) => {
    4. this.componentIdArr.forEach((componentId: string) => {
    5. let nodeController = this.nodeControllerMap.get(componentId);
    6. if (nodeController?.getEmbedId() === touch.embedId) {
    7. nodeController?.postEvent(touch.touchEvent);
    8. }
    9. })
    10. })

高性能知识点

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

工程结构&模块类型

  1. nativeembed // har类型
  2. |---mock
  3. | |---GoodsMock.ets // 数据源
  4. |---model
  5. | |---GoodsModel.ets // 数据类
  6. |---view
  7. | |---NativeEmbedView.ets // 视图层

模块依赖

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

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(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 - 全球开发者的开源社区,开源代码

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

鸿蒙NEXT全套学习资料
微信名片
注:本文转载自blog.csdn.net的让开,我要吃人了的文章"https://blog.csdn.net/weixin_55362248/article/details/142493916"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top