【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(上)

文章目录

  • 前言
  • 一、ArkTS基本介绍
    • 1、 ArkTS组成
    • 2、组件参数和属性
      • 2.1、区分参数和属性的含义
      • 2.2、父子组件嵌套
  • 二、装饰器语法
    • 1.@State
    • 2.@Prop
    • 3.@Link
    • 4.@Watch
    • 5.@Provide和@Consume
    • 6.@Observed和@ObjectLink
      • 代码示例:
        • 示例1:(不使用@Observed和@ObjectLink)
        • 示例2:(使用@Observed和@ObjectLink)
  • 三、总结
  • 四、未完待更


前言

HarmonyOS NEXT(鸿蒙应用)开发快速入门教程ArkTS语法之装饰器篇,基于HarmonyOS NEXT Beta1版本(api 12)讲解。

本文将从前端开发者角度来理解和学习每个语法点,通过举例HarmonyOS NEXT和web端两种领域类似语法的使用,帮助前端开发人员快速入门HarmonyOS NEXT。在每个装饰器讲解上把同一个功能分别用ArkTs和vue 2种代码进行演示,使其更深刻理解每个装饰器的作用,在类比中学习记忆达到无缝衔接。


一、ArkTS基本介绍

ArkTs是鸿蒙开发主要语言,在以TS为语法基础上进行部分扩展和约束,以提升程序执行稳定性和性能。ArkTs可以看成严格模式的TS,并结合声明式UI进行页面布局。ArkTs吸收各家语言优点形成一种全新语法,在ArkTs身上我们到处都能看到web、vue、flutter、安卓等前端领域语法的身影

1、 ArkTS组成

在这里插入图片描述

说明:
1、以@开头为装饰器,装饰器都有固定英文名称,不同装饰器有着不同作用。例如@Entry表示当前组件为页面级别组件(页面路由入口),@Component声明该文件为组件 @State声明一个可引起UI响应式的变量等等
2、struct 后面跟着组件名称,固定写法,struct 类似es6 类里面关键字class, 后面的组件名称可以自定义,内部语法也类似class类语法,包括方法和属性添加
3、UI描述固定放置在build函数里面,换句话说build函数里面主要写布局代码
4、系统组件:一些系统自带的组件例如文字(Text)、按钮(Button)、输入框(TextInput)等,类似web里面dom标签,子组件通过嵌套标签写法引入,组件的属性和事件通过链式调用。

2、组件参数和属性

2.1、区分参数和属性的含义

组件标签函数入参称为组件参数,也即括号内的内容,而点后面的链式调用函数称为属性,事件和属性一样也通过链式函数调用

示例2.1:

  build() {Column(){Button('按钮').type(ButtonType.Capsule).onClick(()=>{console.log('click')})}.width('500px').height('200px').backgroundColor(Color.Black)}

如上述示例所示,'按钮’为组件Button入参,type为Button属性,onClick为Button点击事件,width、height、backgroundColor为组件Column属性。

所有组件都有通用属性,通用属性大部分类似web里的css属性,例如设置组件的尺寸宽高、位置、背景、透明度等。

2.2、父子组件嵌套

父组件花括号{}内写子组件,如示例2.1Column为父组件,Button为子组件,如果没有子组件可以省略{},如示例2.1的Button

示例2.1等价于如下的html写法:

    <div style="height:200px;width:500px;background:black"><button >按钮</button></div>

二、装饰器语法

常用的装饰器语法跟vue很像,本模块将通过ArkTs示例结合web(主要vue)示例演示对比,使其更好的理解和掌握ArkTs装饰器的使用。

1.@State

@State用来装饰变量,通过@State装饰的变量改变后才能触发UI刷新,而普遍变量改变不触发UI刷新,相当于Vue3的ref

语法:@State 变量名:类型=值

//例如
@State sex:string="男"

示例:

ArkTs写法:

@Entry
@Component
struct Demo {@State name:string='小红'//姓名age:number=10//年龄build() {Column({space:10}){Text(`姓名:${this.name}`).fontColor(Color.Black)Text(`年龄${this.age}`).fontColor(Color.Black)Button('点击改变姓名').onClick(()=>{this.name='小明'})Button('点击改变年龄').onClick(()=>{this.age=20})}}
}

等价于

Vue3写法:

<template><div style="display:flex;flex-direction: column;"><span>姓名{{name}}</span><span>年龄{{age}}</span><button @click="onChangeName">点击改变姓名</button><button @click="onChangeAge">点击改变年龄</button></div>
</template>
<script setup>
import {ref} from 'vue'
const name=ref('小红')
let age=10const onChangeName=()=>{name.value='小明'
}
const onChangeAge=()=>{age=20
}</script>

运行效果:
请添加图片描述

上述示例name(姓名)变量用@State修饰而age(年龄)变量为普通变量,当点击改变姓名按钮,姓名变成小红,当点击改变年龄按钮,年龄不变

2.@Prop

@Prop用来定义子组件的入参,和父组件建立单向的同步关系,相当于vue中的prop,区别在于vue中的prop不允许改变值,而鸿蒙中可以随意改变值,但是改变后的值不会同步回其父组件,也就是数据是单向传递。

语法:@Prop 变量名:类型=默认值

@Prop size:number=20

示例:

ArkTs写法:


//父组件
@Entry
@Component
struct Parent {@State city:string='上海'build() {Column({space:20}) {//引入子组件Child({city:this.city})Button('定位').onClick(()=>{this.city='深圳'})}}
}//子组件
@Component
struct Child{@Prop city:string='北京' //默认值北京build() {Column({space:10}) {Text(`当前所处城市:${this.city}`).fontSize(20)}}
}

等价于

Vue3写法:

child.vue(子组件):

<template><div><span>当前所处的城市:{{city}}</span></div>
</template>
<script setup>
const props=defineProps({city:{type:String,default:'北京'}
})</script>

parent.vue(父组件):

<template><div style="display:flex;flex-direction: column;"><Child :city="city"></Child><button @click="onLocation">定位</button></div>
</template>
<script setup>
import {ref} from 'vue'
import Child from './child.vue'
const city=ref('上海')
//定位点击事件
const onLocation=()=>{city.value='深圳'
}</script>
<style scoped></style>        

运行效果:
请添加图片描述

ps:ArkTS支持在同一个文件内自定义多个组件,也可以分出去单独写子组件通过import导入

3.@Link

@Link用来定义子组件入参,和父组件建立双向绑定关系,相当于vue中的v-model,区别在于@Link是直接在子组件内修改数据源,而v-model是语法糖,本质通过事件通知父组件来改变值。

语法:@Link 变量名:类型

@Link loop:boolean

示例:

ArkTs写法:

//父组件
@Entry
@Component
struct Parent {@State value: string = '' //输入内容build() {Column({ space: 20 }) {Text(`输入框值为:${this.value}`)Child({ value: this.value })}.padding(20)}
}//子组件
@Component
struct Child {@Link value: string //输入内容build() {//输入框TextInput({ text: this.value }).onChange((value: string) => { //输入事件监听this.value = value})}
}

等价于

Vue3写法:

child.vue(子组件):

<template><input :value="modelValue" @input="onChange"/>
</template>
<script setup>
const props=defineProps({modelValue:{type:String,default:''}
})const emits=defineEmits(['update:modelValue'])//输入事件监听
const onChange=(e)=>{console.log(e,'e')emits('update:modelValue',e.target.value)
}</script>

parent.vue(父组件):

<template><div style="display:flex;flex-direction: column;"><span>输入框值为:{{value}}</span><Child v-model="value"></Child></div>
</template>
<script setup>
import {ref} from 'vue'
import Child from './child.vue'//输入内容
const value=ref('')</script>
<style scoped></style>        

运行效果:

请添加图片描述

ps:@Link修饰的变量不能设置默认值

4.@Watch

@Watch用于对状态变量的监听,当变量值变化会触发回调。相当于vue中 watch。

语法:
其他装饰器 @Watch(回调函数名) 变量名:类型=值

@Watch(回调函数名) 其他装饰器 变量名:类型=值

推荐@Watch写在其他装饰器后面

@State @Watch("onIndexChange") index:number=0
//监听值改变回调
onIndexChange(){
} 

区别和注意点:
1、@Watch无法获取旧值,相当于无vue-watch的oldValue入参
2、@Watch无法深度监听,相当vue-watch的deep属性为false
3、@Watch无法设置初始化触发,相当vue-watch的immediate属性为false
4、@Watch可监听所有装饰器装饰的状态变量。不允许监听常规变量
5、@Watch对于数组监听能力跟vue2对数组响应式监听一样能监听到push、pop、splice、shift、unshift等数组操作变化

示例:

ArkTs写法:

//父组件
@Entry
@Component
struct Demo {private price: number = 10 //单价@State @Watch('onCountChange')  count:number=1//数量@State total:number=10 //总价//数量变化监听onCountChange(){this.total=this.price*this.count}build() {Column({ space: 20 }) {Text(`单价:¥${this.price}`)Text(`数量:x${this.count}`)Text(`总价:¥${this.total}`)Button('数量+1').onClick(()=>{this.count++})}.padding(20).alignItems(HorizontalAlign.Start)}
}//子组件
@Component
struct Child {@Link value: string //输入内容build() {//输入框TextInput({ text: this.value }).onChange((value: string) => { //输入事件监听this.value = value})}
}

等价于

Vue3写法:

<template><div style="display:flex;flex-direction: column;"><span>单价:¥{{price}}</span><span>数量:x{{count}}</span><span>总价:¥{{total}}</span><button @click="onCountChange">数量+1</button></div>
</template>
<script setup>
import {ref,watch} from 'vue'
//单价
const price=ref(10)
//数量
const count=ref(1)
//总价
const total=ref(10)
//数量+1
const onCountChange=()=>{count.value++
}
watch(count,(newValue,oldValue)=>{total.value=price.value*newValue
})</script>
<style scoped></style>        

运行效果:

请添加图片描述

从上述例子可以看出watch回调函数中无任何入参,获取新值是通过重新访问属性值来获取,而旧值无法获取,这是第一点不足。第二点不足无法深层监听对象,第三点不足只能监听单个值变化,无法像vue3可以监听多个值。好在下一个装饰器语法版本(v2版本)将对这些不足点进行改进并支持,目前v2版本处于试用开发阶段还不成熟这里不过多介绍。

5.@Provide和@Consume

@Provide和@Consume成对使用,作用是把参数往子孙层传递,实现跨层级(多层级)传递。父组件使用@Provide修饰变量参数,子孙组件使用@Consume接收变量参数,跟vue3的Provide+Consume使用机制一样。

两种写法:

// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;// 通过相同的变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;

示例:

ArkTs写法:

//父组件
@Entry
@Component
struct Parent {@Provide('weight') weight: number = 50build() {Column({ space: 20 }) {Text(`父组件体重值:${this.weight}`)Button(`父组件体重+1`).onClick(() => {this.weight++})Child()}.padding(20).alignItems(HorizontalAlign.Start)}
}//子组件
@Component
struct Child {build() {Grandson()}
}//孙组件
@Component
struct Grandson {@Consume('weight') weight: numberbuild() {Column({ space: 20 }) {Text(`孙组件体重值:${this.weight}`)Button(`孙组件体重+1`).onClick(() => {this.weight++})}.margin({ top: 50 })}
}

等价于

Vue3写法:

parent.vue(父组件):

<template><div><span>父组件体重值:{{ weight }}</span><button @click="onAdd">父组件体重+1</button><Child/></div>
</template><script setup>
import { ref,provide } from "vue";
import Child from './child.vue'const weight=ref(50)
provide('weight',weight)
const onAdd=()=>{weight.value++
}</script>

child.vue(子组件):

<template><Grandson/>
</template><script setup>
import Grandson from "./grandson .vue";
</script>

grandson.vue(孙组件)

<template><div><span>孙组件体重值:{{ weight }}</span><button @click="onAdd">孙组件体重+1</button></div></template><script setup>import { ref,inject } from "vue";const weight=inject('weight',50)const onAdd=()=>{weight.value++}</script>

运行效果:

请添加图片描述

ps:@Consume修饰的变量不能设置默认值

6.@Observed和@ObjectLink

对于对象类型的数据劫持鸿蒙和vue不一样,不管是@State、@Prop、@Link或者@Provide+@Consume对于对象类型的数据只能监听到最外层变化,当对象嵌套多层对象内部对象的属性值改变将无法响应UI变化,@Observed和@ObjectLink就是为了解决这个问题而设计的。

使用方法:
1、@Observed用来修饰类(也即TS对象类型),被@Observed装饰的类,可以被观察到属性的变化,每一层的类都需要用@Observed修饰才能生效。
2、@ObjectLink装饰器在子组件中使用,用于装饰@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定,也可以看成子组件的入参变量。
3、@Observed和@ObjectLink要配合自定义子组件使用才能生效,而且每嵌套一层就要抽离出一个子组件引入,简单理解就是每一层数据当入参传入子组件。

语法示例:

@Observed
class xxx{constructor(){}
}

子组件:

 @ObjectLink 变量名:类型

代码示例:

场景设计—— 假设有个学生对象数据,对象里包含姓名、性别、和成绩属性,成绩属性又是个对象,包含语文、数学、英文分数属性。通过改变学生性别和分数观察UI变化。

示例1:(不使用@Observed和@ObjectLink)
//学生对象
class Student {name: string //姓名sex: string //性别score: ScoreData //分数对象constructor(name: string, sex: string, score: ScoreData) {this.name = namethis.sex = sexthis.score = score}
}//分数对象
class ScoreData {math: number //数学chinese: number //语文english: number //英语constructor(math: number, chinese: number, english: number) {this.math = maththis.chinese = chinesethis.english = english}
}@Entry
@Component
struct Demo {//学生对象实例@State student:Student=new Student("王明","男",new ScoreData(80,90,75))build() {Column({space:10}) {Text(`姓名:${this.student.name}`)Text(`性别:${this.student.sex}`)Text(`数学成绩:${this.student.score.math}`)Text(`语文成绩:${this.student.score.chinese}`)Text(`英语成绩:${this.student.score.english}`)Button('改变性别').onClick(()=>{this.student.sex='女'})Button('改变数学成绩').onClick(()=>{this.student.score.math=10})}.width('100%').padding(20).alignItems(HorizontalAlign.Start)}
}

运行效果:
请添加图片描述
从运行效果可以看出性别变了,而数学分数未变,因为数学分数(math属性)属于对象中第二层数据,@State无法观察到多层变化,而性别(sex属性)属于第一层可以观察到变化。

示例2:(使用@Observed和@ObjectLink)
//学生对象
@Observed
class Student {name: string //姓名sex: string //性别score: ScoreData //分数对象constructor(name: string, sex: string, score: ScoreData) {this.name = namethis.sex = sexthis.score = score}
}//分数对象
@Observed
class ScoreData {math: number //数学chinese: number //语文english: number //英语constructor(math: number, chinese: number, english: number) {this.math = maththis.chinese = chinesethis.english = english}
}@Entry
@Component
struct Demo {//学生对象实例@State student: Student = new Student("王明", "男", new ScoreData(80, 90, 75))build() {Column({ space: 10 }) {Text(`姓名:${this.student.name}`)Text(`性别:${this.student.sex}`)ScoreView({data: this.student.score})Button('改变性别').onClick(() => {this.student.sex = '女'})Button('改变数学成绩').onClick(() => {this.student.score.math = 10})Button('改变语文成绩').onClick(() => {this.student.score.chinese--})}.width('100%').padding(20).alignItems(HorizontalAlign.Start)}
}//子组件
@Component
struct ScoreView {@ObjectLink data: ScoreData //分数对象build() {Column() {Text(`数学成绩:${this.data.math}`)Text(`语文成绩:${this.data.chinese}`)Text(`英语成绩:${this.data.english}`)}}
}

运行效果:

请添加图片描述

从运行效果可以看出,因为使用了@Observed和@ObjectLink,所以修改第二层数据(数学和英文成绩)都会响应UI变化。

小结:

通过上面示例演示来看,鸿蒙对嵌套对象场景的开发显得力不从心,如果数据对象是n层就需要自定义n-1个子组件来传递每一层的数据,特别麻烦。好在官方已经注意到这些不足,在下个版本(v2版)提供的新的装饰器@ObservedV2+@Trace解决对象嵌套问题,v2版本目前处于开发试用阶段还没正式发布,这里不过多介绍,有兴趣可以自行查阅官网文档。

ps:对于多层嵌套场景不单单指对象中嵌套对象,还包括对象中嵌套数组或者数组中嵌套对象,因为在js世界里数组也是对象类型。


三、总结

上述6种装饰器语法是开发中比较高频率使用的装饰器,可以看出除了第六个剩下的都可以在vue中找到对应的语法,使用上几乎一样,所以从事前端开发特别是vue技术栈的开发人员可以快速无缝衔接。

四、未完待更

除了上述6种常用装饰器,ArkTs还有一些其他比较重要装饰器,将在下篇博文继续介绍。。。。。。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

未来通信抢先看!遨游通讯2024年中国国际信息通信展亮点剧透

2024年中国国际信息通信展览会将于9月25日-27日在北京国家会议中心举行&#xff0c;本届展会以“推动数实深度融合&#xff0c;共筑新质生产力”为主题。在通信技术日新月异的今天&#xff0c;卫星通信、人工智能、低碳节能等技术理念正引领着通信行业迈向新的高度。遨游通讯作…

【漏洞复现】Casbin casdoor static 任意文件读取漏洞

漏洞描述 Casdoor 是 Casbin 开源社区推出的基于 OAuth 2.0 / OIDC 的中心化的单点登录(SSO)身份验证平台。 Casdoor static 存在任意文件读取漏洞,攻击者通过发送特殊的请求包可以获取服务器中的敏感文件。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵…

Linux C# DAY3

作业 1、 #!/bin/bash mkdir -p ~/dir/dir1 mkdir ~/dir/dir2 cp ./* ~/dir/dir1 cp ./*.sh ~/dir/dir2 cd ~/dir/ tar -cvJf dir2.tar.xz ./dir2 mv dir2.tar.xz ~/dir/dir1/ cd ~/dir/dir1/ tar -xvf dir2.tar.xz 2、 #!/bin/bash head -5 /etc/group | tail -1 sudo mkdi…

CORS漏洞及其防御措施:保护Web应用免受攻击

1. 背景- 什么是CORS&#xff1f; 在当今互联网时代&#xff0c;Web 应用程序的架构日益复杂。一个后端服务可能对应一个前端&#xff0c;也可能与多个前端进行交互。跨站资源共享&#xff08;CORS&#xff09;机制在这种复杂的架构中起着关键作用&#xff0c;但如果配置不当&…

Redis Key的过期策略

Redis 的过期策略主要是指管理和删除那些设定了过期时间的键&#xff0c;以确保内存的有效使用和数据的及时清理。 具体来说&#xff0c;Redis 有三种主要的过期策略&#xff1a;定期删除&#xff08;Scheduled Deletion&#xff09;、惰性删除&#xff08;Lazy Deletion&#…

鸿蒙Harmony-Next 徒手撸一个日历控件

本文将介绍如何使用鸿蒙Harmony-Next框架实现一个自定义的日历控件。我们将创建一个名为CalendarView的组件&#xff08;注意,这里不能叫 Calendar因为系统的日历叫这个&#xff09;,它具有以下功能: 显示当前月份的日历支持选择日期显示农历日期可以切换上一月和下一月 组件…

情感类智能体——你的微信女神

智能体名称&#xff1a;你的微信女神 链接&#xff1a;文心智能体平台AgentBuilder | 想象即现实 (baidu.com)https://agents.baidu.com/agent/preview/RulbsUjIGj4wsinydlBH7AR3NQKFungt 简介 “你的微信女神”是一个直率的智能体&#xff0c;她用犀利而真实的言辞帮助用户…

C++第十一节课 new和delete

一、new和delete操作自定义类型 new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数&#xff08;new会自动调用构造函数&#xff1b;delete会调用析构函数&#xff09; class A { public:A(int a 0): _a(a){cout <&l…

JAVAWeb--前端工程化

一、前端工程化开篇 1.1 什么是前端工程化 前端工程化是使用软件工程的方法来单独解决前端的开发流程中模块化、组件化、规范化、自动化的问题,其主要目的为了提高效率和降低成本。 1.2 前端工程化实现技术栈 前端工程化实现的技术栈有很多,我们采用ES6nodejsnpmViteVUE3route…

【C++ Primer Plus习题】16.10

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> #include <string> #include <…

CefSharp_Vue交互(Element UI)_WinFormWeb应用(2)---置顶和取消置顶(含示例代码)

一、预览 获取winform的置顶参数,和设置置顶参数 1.1 置顶(默认不置顶) 1.2 示例代码

服务器——装新的CUDA版本的方法

服务器——装新的CUDA版本 一、进入 CUDA 版本列表二、根据自己服务器&#xff0c;选择对应的版本和配置三、使用管理员用户&#xff0c;运行下载和安装命令四、查看显卡驱动是否安装4.1 若安装了显卡驱动4.2 若显卡驱动没安装 参考文章 一、进入 CUDA 版本列表 CUDA Toolkit …

数字签名和CA数字证书的核心原理

看了蛋老师的视频就很容易理解了&#xff0c;首先对服务器的公钥和信息进行哈希运算得到一个短字符串&#xff0c;然后用CA机构中的私钥对这一短字符串进行加密就得到了一个数字签名&#xff0c;然后就这个数字签名放到数字证书中&#xff0c;同时服务器的公钥也放在数字证书中…

列表、数组排序总结:Collections.sort()、list.sort()、list.stream().sorted()、Arrays.sort()

列表类型 一.Collections.sort() Collections.sort()用于List类型的排序&#xff0c;其提供了两个重载方法&#xff1a; 1.sort(List<T> list) &#xff08;1&#xff09;List指定泛型时只能指定引用数据类型&#xff0c;也就是说无法用于基本数据类型的排序。 &am…

云韧性,现代云服务不可或缺的组成部分

韧性&#xff0c;一个物理学概念&#xff0c;表示材料在变形或者破裂过程中吸收能量的能力。韧性越好&#xff0c;则发生脆性断裂的可能性越小。 如今&#xff0c;韧性也延伸到企业特质、产品特征等之中&#xff0c;用于形容企业、产品乃至服务的优劣。同样&#xff0c;随着云…

【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略

文章目录 C类与对象前言读者须知RVO 与 NRVO 的启用条件如何确认优化是否启用&#xff1f; 1. 按值传递与拷贝省略1.1 按值传递的概念1.2 示例代码1.3 按值传递的性能影响1.3.1 完全不优化 1.4 不同编译器下的优化表现1.4.1 Visual Studio 2019普通优化1.4.2 Visual Studio 202…

【C语言】⾃定义类型:联合和枚举

⾃定义类型&#xff1a;联合和枚举 1. 联合体1.1 联合体类型的声明1.2 联合体的特点1.3 相同成员的结构体和联合体对⽐1.4 联合体⼤⼩的计算1.5 联合的⼀个练习 2. 枚举类型2.1 枚举类型的声明2.2 枚举类型的优点2.3 枚举类型的使⽤ 1. 联合体 1.1 联合体类型的声明 像结构体…

哪家宠物空气净化器性价比高?希喂、霍尼韦尔和范罗士测评分享

对于家里有宠物的家庭来说&#xff0c;浮毛和异味已经是一件让它们十分头疼的事情了&#xff0c;所以我们在选购宠物空气净化器的时候&#xff0c;总会纠结于哪个品牌性价比高这个问题。毕竟宠物空气净化器是家里的电器&#xff0c;使用年限长&#xff0c;选购时自然要慎重考虑…

【JavaScript】算法之分治、动态规划

一个大问题分成多个小问题&#xff0c;递归解决小问题&#xff0c;将结果合并从而来解决原来的问题 分治 子问题都是独立的 动态规划 把分治优化了【重复的问题&#xff0c;单独保存起来】斐波那契数列 leetcode 习题 分治、动态规划习题

HarmonyOS 应用获取公钥和 MD5 指纹签名信息

鸿蒙版本获取 MD5 指纹和公钥可参考如下方式; 首先,通过 AGC 官网 将所需证书下载至本地; 其次,通过记事本或者文本编译器的方式将其正式打开,将其内容中前两项 BEGIN CERTIFICATE 和 END CERTIFICATE 的段落删除,仅保留最后一段中的内容(包括 BEGIN CERTIFICATE 和 END CERTI…