HarmonyOS Web组件

1. 前言

  众所周知,在Android系统App开发中,我们往往会直接跳转到网页。比如微信给你发了一个链接,默认也是在App之内打开的。很多App就只使用一个WebView作为整体框架,这样开发的好处是,只要使用少量的代码即可完成交互。同样在Harmony系统开发中,使用Harmony的ArkUI框架开发应用的时候,官方为我们提供了一个web组件,提供给开发者使用,通过本文学习,我们将了解并学会如何使用HarmonyOS Web组件进行如下操作:
  (1)在线网页加载
  (2)本地离线网页加载
  (3)Web组件常用属性设置
  (4)客户端与网页之间的双向通信交互

2. Web组件介绍

  Web是提供网页显示能力的组件,具体用法请参考 Web API

2.1. 接口

Web(options: { src: string, controller?: WebController })

2.1.1. 参数

(1)src:是网页资源地址,可以是本地资源,也可以是网络资源
(2)controller:控制器,可以控制Web组件的各种行为,如网页前进、后退等

2.1.2. 加载在线网页

  只需要给src指定引用的网页路径

 Web({ src: 'https://www.baidu.com/', controller: this.controller })

2.1.3. 加载本地网页

  首先在main/resources/rawfile目录下创建一个HTML文件,然后通过$rawfile引用本地网页资源

Web({ src: $rawfile('index.html'), controller: this.controller })

2.1.4. controller:

(1)forward:前进
(2)backward:后退
(3)refresh:刷新
(4)stop:停止
(5)clearHistory:清除历史
(6)runJavaScript:原生页面调用H5页面
(7)zoom(factor: number):设置网页缩放倍数,zoomAccess为true时才生效

2.1.5. 属性

(1)fileAccess:设置是否开启通过$rawfile(filepath/filename)访问应用中rawfile路径的文件, 默认启用
(2)javaScriptAccess:设置是否允许执行JavaScript脚本,默认允许执行
(3)imageAccess:设置是否允许自动加载图片资源,默认允许
(4)zoomAccess:设置是否支持手势进行缩放,默认允许执行缩放
(5)textZoomAtio:设置页面的文本缩放百分比,默认100,表示100%

2.1.6. 事件

  (1)onConfirm事件,网页调用confirm()告警时触发此回调

onConfirm(callback: (event?: { url: string; message: string; result: JsResult }) => boolean)

  参数:
  url:当前显示弹窗所在网页的URL
  message:弹窗中显示的信息
  result:通知Web组件用户操作行为
  返回值:
  当回调返回true时,可以调用系统弹窗能力(包括确认和取消),如自定义弹窗AlertDialog.show;返回false时,触发默认弹窗
(2)onAlert
(3)onBeforeUnload
(4)onConsole

   可以通过runJavaScript执行H5方法,H5页面处理完成之后调用confirm方法,原生页面会回调onConfirm事件,在这个回调事件中做一些逻辑处理,这样就完成了原生界面和H5页面的交互

2.2. Web和JavaScript交互

   如果需要加载的网页在Web组件中运行JavaScript,则必须为Web组件启用JavaScript功能,默认情况下是允许JavaScript执行的

Web({ src:'https://www.baidu.com', controller:this.controller })
    .javaScriptAccess(true)

2.2.1. Web和JavaScript交互

   可以在Web组件中使用runJavaScript方法调用JS方法

 this.controller.runJavaScript({
          script: 'test()',
          callback: (result: string)=> {
            this.webResult = result;
          }});

   调用HTML文件中的test方法并将结果返回给Web组件

2.2.2. Web和JavaScript交互

   可以使用registerJavaScriptProxy将Web组件中的JavaScript对象注入到window对象中,这样网页中的JS就可以直接调用该对象了
   要想registerJavaScriptProxy方法生效,须调用refresh方法
   原生调用:

@Entry
@Component
struct WebPage {
  @State dataFromHtml: string = ''
  controller: WebController = new WebController()
  testObj = {
    test: (data) => {
      this.dataFromHtml = data
      return 'ArkUI Web Component';
    },
    toString: () => {
      console.log('Web Component toString');
    }
  }
 
  build() {
    Column() {
      Text(this.dataFromHtml).fontSize(20)
      Row() {
        Button('Register JavaScript To Window').onClick(() => {
          this.controller.registerJavaScriptProxy({
            object: this.testObj,
            name: 'objName',
            methodList: ['test', 'toString'],
          });
          this.controller.refresh();
        })
      }
 
      Web({ src: $rawfile('index.html'), controller: this.controller })
        .javaScriptAccess(true)
    }
  }
}

   Htnl代码:

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<button onclick="htmlTest()">调用Web组件里面的方法</button>
</body>
<script type="text/javascript">
    function htmlTest() {
        str = objName.test("param from Html");
    }
</script>
</html>

2.2.3. 案例

@Entry
@Component
struct WebPage {
  @State dataFromHtml: string = ''
  controller: WebController = new WebController()
  testObj = {
    test: (data) => {
      this.dataFromHtml = data
      return 'ArkUI Web Component';
    }, controller: this.controller })
        .javaScriptAccess(true)
    }
  }
}

3. 基础使用

3.1. 创建组件

  在pages目录下创建WebComponent .ets的Page页面, 页面上放一个Web组件。在Web组件中通过src指定引用的网页路径,controller为组件的控制器,通过controller绑定Web组件,用于调用Web组件的方法。

import webVeb from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
  webController: webVeb.WebviewController =
    new webVeb.WebviewController();
  build() {
    Column() {
      /**
       * 组件创建时,
       * (1)网络加载https://www.douban.com/
       * (2)本地加载$rawfile('app/html/login.html')
       */
      Web({ src: $rawfile('app/html/login.html'),
        controller: this.webController })
    }
  }
}

3.2. 添加权限

  使用Web组件,访问在线网页,需要给应用配置网络权限,访问在线网页时需添加网络权限:ohos.permission.INTERNET。

在这里插入图片描述

 "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:app_name",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when": "inuse"
        }
      },
    ]

3.3. 设置样式和属性

  Web组件的使用需要添加丰富的页面样式和功能属性。设置height、padding样式可为Web组件添加高和内边距,设置fileAccess属性可为Web组件添加文件访问权限,设置javaScriptAccess属性为true使Web组件具有执行JavaScript代码的能力。

import webVeb from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
  webController: webVeb.WebviewController =
    new webVeb.WebviewController();
  fileAccess: boolean = true;
  build() {
    Column() {
      Text('Hello world!')
        .fontSize(20)
      /**
       * 组件创建时,
       * (1)网络加载https://www.douban.com/
       * (2)本地加载$rawfile('app/html/login.html')
       */
      Web({ src: $rawfile('app/html/login.html'),
        controller: this.webController })
        // 设置高和内边距
        .height(500)
        .padding(20)
          // 设置文件访问权限和脚本执行权限
        .fileAccess(this.fileAccess)
        .javaScriptAccess(true)
    }
  }
}

3.4. 添加事件和方法

  为Web组件添加onProgressChange事件,该事件回调Web引擎加载页面的进度值。将该进度值赋值给Progress组件的value,控制Progress组件的状态。当进度为100%时隐藏Progress组件,Web页面加载完成。

import webVeb from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
  webController: webVeb.WebviewController =
    new webVeb.WebviewController();
  fileAccess: boolean = true;
  @State progress: number = 0
  @State hideProgress: boolean = true
  build() {
    Column() {
      Progress({ total: 100, value: this.progress })
        .color('#ff5cea20')
        .visibility(this.hideProgress
          ? Visibility.None : Visibility.Visible)
      /**
       * 组件创建时,
       * (1)网络加载https://www.douban.com/
       * (2)本地加载$rawfile('app/html/login.html')
       */
      Web({ src: $rawfile('app/html/login.html'),
        controller: this.webController })
        // 设置文件访问权限和脚本执行权限
        .fileAccess(this.fileAccess)
        .javaScriptAccess(true)
        .height('100%')
          // 添加onProgressChange事件
        .onProgressChange(e => {
          this.progress = e.newProgress
          // 当进度100%时,进度条消失
          if (this.progress == 100) {
            this.hideProgress = true
          } else {
            this.hideProgress = false
          }
        })
    }.backgroundColor('0xFFFFFF')
  }
}

3.5. 访问本地Html

  实现了一个加载本地网页文件,然后Html网页中调用客户端的方法,进行了一个关闭页面和拉起系统相册的功能,下面开始讲下代码实现。

3.5.1. 本地html文件创建

  在entry/src/main/resources/rawfile目录下,我们创建一个index.html文件

在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <script type="text/javascript" src="./static/js/init-rem.js"></script>
    <style type="text/css">
        body{
            display: flex;
            flex-direction: column;
        }
        .title {
            color: black;
           font-size: 0.34rem;
        }
        .btn-layout {
            color: red;
            font-size: 0.32rem;
            margin-top: 0.5rem;
        }
        .btn-layout2 {
            color: blue;
            font-size: 0.32rem;
            margin-top: 0.5rem;
        }
    </style>
</head>
<body>
<p class="title">这个是来自本地的html文件</p>
<button class="btn-layout" type="button"
        onclick="window.jsBridge.closePage()">点击调用原生关闭页面
</button>
<button class="btn-layout2" type="button"
        onclick="window.jsBridge.jumpSystemPicture()">
    点击拉起原生系统相册
</button>
</body>
</html>

3.5.2. 本地html文件加载,JS对象注入,Html使用JS对象调用客户端方法

  创建一个LocalWebPage页面,加载index.html 文件,如果需要进行网页跟客户端进行交互,我们需要设置往Html中注入一个JS对象,具体如下:

import webVeb from '@ohos.web.webview';
import common from '@ohos.app.ability.common';
import router from '@ohos.router';
@Entry
@Component
struct WebComponent {
  webController: webVeb.WebviewController =
    new webVeb.WebviewController();
  fileAccess: boolean = true;
  @State progress: number = 0
  @State hideProgress: boolean = true
  jsBridge = {
    jumpSystemPicture() {
      let context = getContext(this) as common.UIAbilityContext;
      let want  = {
        "deviceId": "",
        "bundleName": "",
        "abilityName": "",
        "uri": "",
        "type": "image/*",
        "action": "android.intent.action.GET_CONTENT",
        "parameters":{},
        "entities":[]
      };
      context.startAbility(want);
    },
    closePage() {
      router.back()
    }
  }
  build() {
    Column() {
      Progress({ total: 100, value: this.progress })
        .color('#ff5cea20')
        .visibility(this.hideProgress
          ? Visibility.None : Visibility.Visible)
      /**
       * 组件创建时,
       * (1)网络加载https://www.douban.com/
       * (2)本地加载$rawfile('app/html/login.html')
       */
      Web({ src: $rawfile('app/index.html'),
        controller: this.webController })
        // 设置文件访问权限和脚本执行权限
        .fileAccess(this.fileAccess)
        .javaScriptAccess(true)
        .height('100%')
          // 添加onProgressChange事件
        .onProgressChange(e => {
          this.progress = e.newProgress
          // 当进度100%时,进度条消失
          if (this.progress == 100) {
            this.hideProgress = true
          } else {
            this.hideProgress = false
          }
        })
        //JS对象注入,Html使用JS对象调用客户端方法
        .javaScriptAccess(true)
        .javaScriptProxy({
          object: this.jsBridge,
          name: "jsBridge",
          methodList: ["closePage","jumpSystemPicture"],
          controller: this.webController
        })    
    }.backgroundColor('0xFFFFFF')
  }
}

  这里我们定义了一个JS对象jsBridge ,定义了两个方法,jumpSystemPicture 和closePage,分别用于html 拉起系统相册和关闭客户端页面,然后使用Web的 javaScriptProxy方法进行JS对象注入设置,具体的配置如上述代码,需要配置对象名称,注入方法。
  看下上文中Html 调用JS的代码,比如调用客户端的关闭页面方法,使用
  window.jsBridge.closePage() 进行触发。

3.5.3. 客户端调用本地Html网页中的JS方法

  在onPageEnd事件中添加runJavaScript方法。onPageEnd事件是网页加载完成时的回调,runJavaScript方法可以执行HTML中的JavaScript脚本。当页面加载完成时,触发onPageEnd事件,调用HTML文件中的test方法,在控制台打印信息。

import webVeb from '@ohos.web.webview';
import common from '@ohos.app.ability.common';
import router from '@ohos.router';
@Entry
@Component
struct WebComponent {
  webController: webVeb.WebviewController =
    new webVeb.WebviewController();
  fileAccess: boolean = true;
  @State progress: number = 0
  @State hideProgress: boolean = true
  jsBridge = {
    jumpSystemPicture() {
      let context = getContext(this) as common.UIAbilityContext;
      let want = {
        "deviceId": "",
        "parameters": {},
        "entities": []
      };
      context.startAbility(want);
    },
        controller: this.webController })
        // 设置文件访问权限和脚本执行权限
        .fileAccess(this.fileAccess)
        .javaScriptAccess(true)
        .height('100%')
          // 添加onProgressChange事件
        .onProgressChange(e => {
          this.progress = e.newProgress
          // 当进度100%时,进度条消失
          if (this.progress == 100) {
            this.hideProgress = true
          } else {
            this.hideProgress = false
          }
        })
          //JS对象注入,Html使用JS对象调用客户端方法
        .javaScriptAccess(true)
        .javaScriptProxy({
          object: this.jsBridge, "jumpSystemPicture"],
          controller: this.webController
        })
        .onPageEnd(e => {
          // test()在index.html中定义
          this.webController.runJavaScript('test()');
          console.info('url: ', e.url);
        })
    }.backgroundColor('0xFFFFFF')
  }
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <meta name="viewport"
          content="width=device-width,user-scalable=no"/>
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <script type="text/javascript" src="./static/js/init-rem.js"></script>
    <script type="text/javascript" src="./static/js/vconsole.min.js"></script>
    <script type="text/javascript">
        var vc = new VConsole()
    </script>
    <style type="text/css">
        body {
            display: flex;
            flex-direction: column;
        }
        .title {
            color: black;
            font-size: 0.34rem;
        }
        .btn-layout {
            color: red;
            font-size: 0.32rem;
            margin-top: 0.5rem;
        }
        .btn-layout2 {
            color: blue;
            font-size: 0.32rem;
            margin-top: 0.5rem;
        }
    </style>
</head>
<body>
<p class="title">这个是来自本地的html文件</p>
<button class="btn-layout" type="button"
        onclick="window.jsBridge.closePage()">
    点击调用原生关闭页面
</button>
<button class="btn-layout2" type="button"
        onclick="window.jsBridge.jumpSystemPicture()">
    点击拉起原生系统相册
</button>
<script type="text/javascript">
    function test() {
        console.info('Ark Web Component');
    }
</script>
</body>
</html>

在这里插入图片描述

在这里插入图片描述

3.6. Web组件H5层与应用层进行相互通讯

在这里插入图片描述

3.6.1. 鸿蒙应用向H5页面发送数据

  在创建的Web页面中使用 runJavaScript() 方法可直接触发 H5 页面中的方法

 Button("向H5层发送数据")
          .onClick(() => {
            this.webController
              .runJavaScript(`sendH5Msg("${this.input}")`)
          }).margin(10)

3.6.2. H5页面向鸿蒙应用发送数据

  在 H5 页面中 执行 confirm() 弹窗,在 Web组件 中执行 onConfirm 事件并通过 Promise 方式返回脚本执行的结果。
  返回结果为一个对象,其中url为当前web组件加载的页面地址,message为H5中传递返回的结果。

/**
     * 给原生应用传递数据
     */
    function toHmMsg() {
        let obj = {
            name: "张三", age: "20"
        }
        confirm(JSON.stringify(obj))
    }

3.6.3. 完整代码

(1)Harmony代码

import webVeb from '@ohos.web.webview';
// 实现Web组件H5层与应用层进行相互通讯
@Entry
@Component
struct WebComponent4 {
  webController: webVeb.WebviewController =
    new webVeb.WebviewController();
  @State content: string = ""
  @State input: string = ""
  build() {
    // H5层
    Column() {
      Column() {
        Text("H5层")
        Web({ src: $rawfile('app/index4.html'),
          controller: this.webController })
          .onConfirm((e: any) => {
            console.log("lvs>" + JSON.stringify(e))
            this.content = e['message']
            return true
          })
      }
      .height('50%')
      .width('100%')
      .padding(10)
      .margin(10)
      .border({ width: 1 })
      // 应用层
      Column() {
        Text("应用层")
        TextInput({ placeholder: "请输入数据" })
          .onChange((e => {
            this.input = e
          }))
        Button("向H5层发送数据")
          .onClick(() => {
            this.webController
              .runJavaScript(`sendH5Msg("${this.input}")`)
          }).margin(10)
        Row().width("100%").height(1)
          .backgroundColor("#ddd").margin(10)
        Text("接受H5传递的内容:"+this.content)
      }
      .height('50%')
      .width('100%')
      .padding(10)
      .margin(10)
      .border({ width: 1 })
    }
    .height('100%')
    .padding(20)
    .backgroundColor('0xFFFFFF')
  }
}

(2)Html 代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <meta name="viewport"
          content="width=device-width,user-scalable=no"/>
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <script type="text/javascript" src="./static/js/init-rem.js"></script>
    <script type="text/javascript" src="./static/js/vconsole.min.js"></script>
    <script type="text/javascript">
        var vc = new VConsole()
    </script>
    <style type="text/css">
        .divCon {
            width: 100px;
            height: 100px;
            background: #ddd;
            margin-top: 20px;
        }
    </style>
</head>
<body>
<script>
    /**
     * 给原生应用传递数据
     */
    function toHmMsg() {
        let obj = {
            name: "张三", age: "20"
        }
        confirm(JSON.stringify(obj))
    }
    /**
     * 接受原生发送数据
     * @param msg
     */
    function sendH5Msg(msg) {
        document.getElementById("content_id").innerText = "你好" + msg
    }
</script>
<div>
    <button onclick="toHmMsg()">给原生应用传递数据</button>
    <div id="content_id" class="divCon"></div>
</div>
</body>
</html>

  上面方法只提到了调用网页中的JS方法,感兴趣的评论区留意讨论,一起学习,相互探讨,共同进步。有时间我再补充讲解下。

原文地址:https://blog.csdn.net/qq_36158551/article/details/135878343

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读1.4k次。被@Observed装饰的类,可以被观察到属性的变化;子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中是属性,这个属性同样也需要被@Observed装饰。单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。_鸿蒙ark对象数组
文章浏览阅读1k次。Harmony OS_harmonyos创建数据库
文章浏览阅读1.1k次,点赞25次,收藏23次。自定义组件Header.ets页面(子组件)//自定义组件@Component//组件声明private title:ResourceStr//接收的参数build(){Row() {index.ets(父组件)//导入自定义组件@Entry@Componentbuild() {Column() {/*** 1. 自定义组件调用-----自定义组件------* 2. 在调用的组件上设置样式*/ShopTitle({ title: '商品列表' })
文章浏览阅读952次,点赞11次,收藏25次。ArkUI是一套构建分布式应用界面的声明式UI开发框架。它使用极简的UI信息语法、丰富的UI组件、以及实时界面预览工具,帮助您提升移动应用界面开发效率30%。您只需使用一套ArkTS API,就能在Android、iOS、鸿蒙多个平台上提供生动而流畅的用户界面体验。_支持ios 安卓 鸿蒙next的跨平台方案
文章浏览阅读735次。​错误: 找不到符号符号: 变量 Layout_list_item位置: 类 ResourceTable_错误: 找不到符号 符号: 变量 resourcetable 位置: 类 mainabilityslice
文章浏览阅读941次,点赞23次,收藏21次。harmony ARKTS base64 加解密_鸿蒙 鸿蒙加解密算法库
文章浏览阅读860次,点赞21次,收藏24次。使用自定义布局,实现子组件自动换行功能。图1自定义布局的使用效果创建自定义布局的类,并继承ComponentContainer,添加构造方法。//如需支持xml创建自定义布局,必须添加该构造方法实现ComponentContainer.EstimateSizeListener接口,在onEstimateSize方法中进行测量。......@Override//通知子组件进行测量//关联子组件的索引与其布局数据idx++) {//测量自身。_鸿蒙javaui
文章浏览阅读917次,点赞25次,收藏25次。这里需要注意的是,真机需要使用华为侧提供的测试机,测试机中会安装纯鸿蒙的系统镜像,能够体验到完整的鸿蒙系统功能,纯鸿蒙应用目前还不能完美地在 HarmonyOS 4.0 的商用机侧跑起来。当前,真机调试需要使用华为侧提供的测试机,测试机中会安装纯鸿蒙的系统镜像,能够体验到完整的鸿蒙系统功能,纯鸿蒙应用目前还不能完美地在 HarmonyOS 4.0 的商用机侧跑起来。另外,由于样式的解析是基于组件文件的纬度的,因此样式文件只能应用于被其引用的组件文件中,而不能跨文件应用,并且样式文件也只支持类选择器。_鸿蒙 小程序
文章浏览阅读876次,点赞17次,收藏4次。2. HarmonyOS应用开发DevEcoStudio准备-1HUAWEI DevEco Studio为运行在HarmonyOS和OpenHarmony系统上的应用和服务(以下简称应用/服务)提供一站式的开发平台。
文章浏览阅读811次。此对象主要映射JSON数组数据,比如服务器传的数据是这样的。_arkts json
文章浏览阅读429次。鸿蒙小游戏-数字华容道_华为鸿蒙手机自带小游戏
文章浏览阅读1.1k次,点赞24次,收藏19次。Ability是应用/服务所具备的能力的抽象,一个Module可以包含一个或多个Ability。
文章浏览阅读846次。本文带大家使用MQTT协议连接华为IoT平台,使用的是E53_IA1 智慧农业扩展板与 BearPi-HM_Nano 开发主板_mqtt 如何对接第三方iot平台
文章浏览阅读567次。HarmonyOS_arkts卡片
文章浏览阅读1k次,点赞19次,收藏20次。ArkTS开发鸿蒙OS连接mongoDB(后端node.js)2024最新教程
文章浏览阅读1.2k次,点赞23次,收藏15次。HarmonyOS与OpenHarmony(1)本质上的不同是:HarmonyOS是鸿蒙操作系统,而OpenHarmony则是从开源项目。这里可以联想一下Android,比如小米手机在Android开源系统的基础上开发了MIUI的手机操作系统,HarmonyOS就类似于MIUI,OpenHarmony类似Android基础底座。(2)HarmonyOS:是双框架,内聚了AOSP(Android Open Source Project )和OpenHarmony等。_鸿蒙模拟器开了怎么跑代码
文章浏览阅读1.1k次,点赞21次,收藏21次。鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Navigation组件。
文章浏览阅读2k次。由于之前的哥们匆忙离职了,所以鸿蒙手表项目的新版本我临时接过来打包发布,基本上之前没有啥鸿蒙经验,但是一直是做Android开发的,在工作人员的指导下发现打包配置基本上和Android一样,所以这些都不是问题,这里记录一下使用过程中遇到的问题。!过程和遇到的问题基本上都讲解了,关机睡觉,打卡收工。_鸿蒙系统adb命令
文章浏览阅读7.3k次,点赞9次,收藏29次。39. 【多选题】_column和row容器中,设置子组件在主轴方向上的对齐格式
文章浏览阅读1.1k次,点赞13次,收藏24次。18.鸿蒙HarmonyOS App(JAVA)日期选择器-时间选择器点击button按钮显示月份与获取的时间。_harmonyos农历获取