黑马程序员鸿蒙4.0视频学习笔记,供自己回顾使用。
鸿蒙harmony开发文档指南
DevEco Studio下载地址
选择或者安装环境
选择和下载SDK
安装总览
编辑器界面
//string 、number、boolean、any、union、Object、Array
let s: string = 'hello world'
const ss: string = 'hello world'//const 代表常量
//any,个人不建议使用,代码量庞大后导致代码逻辑混乱
let a:any = '不确定类型,可能是任意类型'
//union
let u:string|number|boolean = '联合类型,可能是其中一种'
//Object,对象类型
let car = {brand:'问界',Price:199999}
console.log(car.brand)
console.log(car['brand'])
//Array:数组
let cars: Array<string> = ['问界','阿维塔']
let price: number[] = [199999,299999]
console.log(cars[0])
console.log(price[1])
//在TypeScript中,空字符串、数字0、null、undefined都被认为是false,其它值则为true
//if-else,写吐了不想写
if(){}else{}
if(){}else if(){}else{}
//switch
let season:string = '冬天'
switch(season){
case '春天':{
console.log('你的笑容那么美,恰好与春风撞了个满怀')
break
}
case '夏天':{
console.log('玫瑰到了花期,我很想你')
break
}
case '秋天':{
console.log('盛夏欠你的温柔,让秋风徐徐来还。')
break
}
default{
console.log('情话是学的,但爱你是真的')
break
}
}
//for
for(let i = 0;i<100;i++){
console.log('拥有'+i+'个男(女)模对象')
}
// for-in
let cars: string[] = ['问界','阿维塔']
for(const i in cars){
console.log(cars[i])
}
//for-of
for(const car of cars){
console.log(car)
}
//while
let i = 1;
while(i <= 100){
console.log('拥有'+i+'个男(女)模对象')
i++;
}
//无返回值
function func1(car:string):void{
console.log(car)
}
fun1('问界')
//有返回值
function func2(x: number,y:number):number{
return x+y
}
let count = func2(1,1)
console.log('1+1=3?'+'1+1='+count)
//简写版,箭头函数
let func3 = (car:string) => {
console.log(car)
}
func3('阿维塔')
//函数可选参数
function func4(car?:string){
car = car?car:'哦莫'
console.log(car)
}
func4()
func4('link')
//函数可选参数,提供默认值
function func5(car:string='哦莫'){
console.log(car)
}
func5()
func5('link')
//定义枚举
enum GamesConsole{
SWITCH:1999,
PS5:2999,
XBOXONE:2999
}
//定义接口,抽象方法接受枚举参数
interface Price{
//类和对象里的函数不需要加function
showPS5Price(price:GamesConsole):void
}
//实现接口
class Article implements Price{
showPS5Price(price:GamesConsole):void{
console.log('ps5的价格是:'+price)
}
}
//初始化对象
let p:Price = new Article()
//调用方法,传递枚举参数
p.showPrice(GamesConsole.PS5)
//父类
class Rectangle{
//成员变量
private width:number
private length:number
//构造函数
constructor(width:number,length:number){
this.width=width
this.length=length
}
//成员方法
public area():number{
return this.width * this.length
}
}
//子类
class Square extends Rectangle{
constructor(side:number){
//调用父类构造
super(side,side)
}
}
let s = new Square(10)
console.log(s.area())
通用功能抽取到单独的ts文件,每个文件都是一个模块(module)。
模块可以相互加载,提高代码复用性。
//rectangle.ts
//定义类,通过export导出
export class Rectangle{
//成员变量
private width:number
private length:number
//构造函数
constructor(width:number,length:number){
this.width=width
this.length=length
}
}
//定义工具方法,通过export导出
export function area(rec:Rectangle):number{
return rec.width * rec.length
}
//index.ts
//通过import导入,from后面写文件的地址
import {Rectangle,area} from '../rectangle'
//创建Rectangle对象
let r = new Rectangle(10,10)
//调用area方法
console.log('面积为:'+area(r))
create project -> empty ability
Index.ets文件解读
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(()=>{
//...处理事件
if (this.message == 'Hello World') {
this.message = '你好 世界'
}else {
this.message = 'Hello World'
}
})
}
.width('100%')
}
.height('100%')
}
}
Image:图片显示组件
1.声明Image组件并设置图片源:
Image(src: string|PixelMap|Resource)
① string格式,通常用来加载网络图片,需要申请网络访问权限: ohos.permission.INTERNET
Image('https://xxx . png' )
② PixelMap格式,可以加载像素图,常用在图片编辑中
Image(PixelMapObeject)
③ Resource格式,加载本地图片,推荐使用
Image($r('app.media.mate60'))
Image($rawfile('mate60.png'))
2.添加图片属性
Image($r('app .media.icon'))
.width(100) //宽度
.height(120) //高度
.borderRadius(10) // 边框圆角
.interpolation(ImageInterpolation.High) // 图片插值
Text:文本显示组件
1.声明Text组件并设置文本内容
Text(content?:string|Resource)
①string格式,直接填写文本内容
Text('今天天气很好呀!')
②Resource格式,读取本地资源文件
Text($r('app.string.hello'))
2。添加文本属性
Text('注册账号')
.lineHeight(32) // 行高
.fontSize(20) // 字体大小
.fontColor('#ff1876f8') // 字体颜色
.fontWeight(FontWeight.Medium) // 字体粗细
TextInput:文本输入框
1.声明TextInput组件
TextInput( {placeholder?: ResourceStr,text?: ResourceStr})
①placeHoder:输入框无输入时的提示文本
TextInput([placeholder:'请输入账号或手机号'})
②text: 输入框当前的文本内容
TextInput({text: '1234567890'})
2.添加属性和事件
TextInput({text:当前输入文本)
.width(150) //宽
.height(30) // 高
.backgroundColor('#FFF') // 背景色
.type(InputType.Password)//输入框类型
.onChange(value=>{
//value是用户输入的文本内容
})
名称 | 描述 |
---|---|
Normal | 基本输入模式。支持输入数字、字母、下划线、空格、特殊字符。 |
Password | 密码输入模式。支持输入数字、字母、下划线、空格、特殊字符。 |
邮箱地址输入模式。支持数字,字母,下划线,以及@字符。 | |
Number | 纯数字输入模式。 |
PhoneNumber9+ | 电话号码输入模式。支持输入数字、+、-、*、#,长度不限。 |
Button:按钮组件
1.声明Button组件,label是按钮文字:
Button(label?:ResourceStr)
① 文字型按钮
Button('点我')
② 自定义按钮,在Button内嵌套其它组件
Button(){
Image($r('app.media.search')).width(20).margin(10)
}
2.添加属性和事件
Button('点我')
.width(100)
.height(30)
.type(ButtonType.Normal)//按钮类型
.onclick(()=>{
//处理点击事件
})
Slider:滑动条组件
Slider(options?:SliderOptions)
Slider({
min:0,//最小值
max:100,//最大值
value:30,//当前值
step:10,//滑动步长
style:SliderStyle.OutSet,//Inset
direction:Axis.Horizontal,//Vertical
reverse:false//是否反向滑动
})
.width('90%')
.showTips(true)//是否展示value百分比提示
.blockColor('#36D')
.onChangge(value=>{
//value就是当前滑块值
})
属性方法名 | 说明 | 参数 |
---|---|---|
justifyContent | 设置子元素在主轴方向的对其格式 | FlexAlign枚举 |
alignItems | 设置子元素在交叉轴方向的对其格式 | Row容器使用VerticalAlign枚举 |
alignItems | 设置子元素在交叉轴方向的对其格式 | Column容器使用HorizontalAlign枚举 |
FlexAlign枚举:
FlexAlign.Start
FlexAlign.Center
FlexAlign.End
FlexAlign.SpaceBetween
FlexAlign.SpaceAround
FlexAlign.SpaceEvenly
HorizontalAlign枚举:
HorizontalAlign.Start
HorizontalAlign.Center
HorizontalAlign.End
VerticalAlign枚举:
VerticalAlign.start
VerticalAlign.Center
VerticalAlign.End
列表(List)是一种复杂容器,具备以下特点:
① 列表项(ListItem)数量过多超出屏幕后,会自动提供滚动功能
②列表项(ListItem)既可以纵向排列,也可以横向排列
List({space:10}){
ForEach([1,2,3,4],item => {
ListItem(){
//列表项内容,只能包含一个根组件
Text('ListItem')
}
})
}
.width('100%')
@Buider
@style
@Extend不仅可以写特有属性方法还可以写事件方法
在声明式UI中,是以状态驱动视图更新:
状态(state):指驱动视图更新的数据(被装饰器标记的变量)
视图(View):基于UI描述渲染得到用户界面
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Text(this.message)
.onClick(()=>{
this.message == 'Hello World'?this.message = '你好 世界':this.message = 'Hello World'
})
}
}
说明:
@State装饰器标记的变量必须初始化,不能为空值。
@State支持Object、class、string、number、boolean、enum类型已经这些类型的数组。
嵌套类型以及数组中的对象属性无法触发视图更新。
如果做过vue开发应该很好理解。
下个目录所需要的案例
// 任务类
class Task{
static id:number = 1
// 任务名称
name:string = `任务${Task.id++}`
// 任务状态:是否完成
finished:boolean = false
}
// 统一的卡片样式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius:6,color:'#1F000000',offsetX:2,offsetY:4})
}
// 任务完成样式
@Extend(Text) function finishedTask(){
.decoration({type:TextDecorationType.LineThrough})
.fontColor('#B1B2B1')
}
@Entry
@Component
struct PropPage {
@State message: string = 'Hello World'
// 总任务数量
@State totalTask:number = 0
// 已完成任务数量
@State finishTask:number = 0
// 任务数组
@State tasks:Task[] = []
handleTaskChange(){
// 更新任务总数量
this.totalTask = this.tasks.length
// 更新已完成任务数量
this.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column({space:10}) {
// 任务进度卡片
Row(){
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
// 层叠容器
Stack(){
Progress({
value:this.finishTask,
total:this.totalTask,
type:ProgressType.Ring
})
.width(100)
Row(){
Text(this.finishTask.toString())
.fontColor('#36D')
.fontSize(24)
Text(' / '+this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({top:20,bottom:10})
.justifyContent(FlexAlign.SpaceEvenly)
// 新增任务按钮
Button('新增任务')
.width(200)
.onClick(()=>{
this.tasks.push(new Task())
// 更新任务总数量
// this.totalTask = this.tasks.length
this.handleTaskChange()
})
// 任务列表
// 任务列表List版本
List({space:10}){
ForEach(
this.tasks,
(item:Task,index) =>{
ListItem(){
Row(){
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val=>{
// 更新当前任务状态
item.finished = val
// 更新已完成任务数量
// this.finishTask = this.tasks.filter(item => item.finished).length
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({end:this.DeleteButton(index)})
}
)
}
.width('100%')
.alignListItem(ListItemAlign.Center)
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
@Builder DeleteButton(index: number){
Button(){
Image($r('app.media.ic_public_delete_filled'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(()=>{
this.tasks.splice(index,1)
this.handleTaskChange()
})
}
}
状态管理
当父子组件之间需要数据同步时,可以使用@Prop和@Link装饰器:
@Prop | @Link | |
---|---|---|
同步类型 | 单向同步 | 双向同步 |
允许修饰的变量类型 | 1. @Prop只支持string、number、boolean、enum类型 。2.父组件对象类型,子组件对象属性。3.不可以是数组、any | 1.父子类型一致:string、number、boolean、enum、object、class,以及他们的数组。2.数组中元素增、删、替换会引起刷新。 3.嵌套类型以及数组中的对象属性无法触发视图更新 |
初始化方式 | 不允许子组件初始化 | 父组件传递,禁止子组件初始化 |
// 任务类
class Task{
static id:number = 1
// 任务名称
name:string = `任务${Task.id++}`
// 任务状态:是否完成
finished:boolean = false
}
// 统一的卡片样式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius:6,color:'#1F000000',offsetX:2,offsetY:4})
}
// 任务完成样式
@Extend(Text) function finishedTask(){
.decoration({type:TextDecorationType.LineThrough})
.fontColor('#B1B2B1')
}
@Entry
@Component
struct PropPage {
@State message: string = 'Hello World'
// 总任务数量
@State totalTask:number = 0
// 已完成任务数量
@State finishTask:number = 0
build() {
Column({space:10}) {
// 任务进度卡片
TaskStatistics({finishTask:this.finishTask,totalTask:this.totalTask})
// 任务列表
TaskList({finishTask:$finishTask,totalTask:$totalTask})
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
}
@Component
struct TaskStatistics {
@Prop finishTask:number
@Prop totalTask:number
build(){
Row(){
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
// 层叠容器
Stack(){
Progress({
value:this.finishTask,
total:this.totalTask,
type:ProgressType.Ring
})
.width(100)
Row(){
Text(this.finishTask.toString())
.fontColor('#36D')
.fontSize(24)
Text(' / '+this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({top:20,bottom:10})
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
@Link finishTask:number
@Link totalTask:number
// 任务数组
@State tasks:Task[] = []
handleTaskChange(){
// 更新任务总数量
this.totalTask = this.tasks.length
// 更新已完成任务数量
this.finishTask = this.tasks.filter(item => item.finished).length
}
build(){
Column(){
// 新增任务按钮
Button('新增任务')
.width(200)
.onClick(()=>{
this.tasks.push(new Task())
// 更新任务总数量
// this.totalTask = this.tasks.length
this.handleTaskChange()
}).margin({bottom:10})
// 任务列表List版本
List({space:10}){
ForEach(
this.tasks,
(item:Task,index) =>{
ListItem(){
Row(){
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val=>{
// 更新当前任务状态
item.finished = val
// 更新已完成任务数量
// this.finishTask = this.tasks.filter(item => item.finished).length
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({end:this.DeleteButton(index)})
}
)
}
.width('100%')
.alignListItem(ListItemAlign.Center)
.layoutWeight(1)
}
}
@Builder DeleteButton(index: number){
Button(){
Image($r('app.media.ic_public_delete_filled'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(()=>{
this.tasks.splice(index,1)
this.handleTaskChange()
})
}
}
@Provide和Consume可以跨组件提供类似于@State和@Link的双向同步
// 任务类
class Task{
static id:number = 1
// 任务名称
name:string = `任务${Task.id++}`
// 任务状态:是否完成
finished:boolean = false
}
// 统一的卡片样式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius:6,color:'#1F000000',offsetX:2,offsetY:4})
}
// 任务完成样式
@Extend(Text) function finishedTask(){
.decoration({type:TextDecorationType.LineThrough})
.fontColor('#B1B2B1')
}
statInfo{
// 总任务数量
totalTask:number = 0
// 已完成任务数量
finishTask:number = 0
}
@Entry
@Component
struct PropPage {
//统计信息
@Provide state:StatInfo = new StatInfo()
build() {
Column({space:10}) {
// 任务进度卡片
TaskStatistics()//直接不需要传参
// 任务列表
TaskList()//直接不需要传参
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
}
@Component
struct TaskStatistics {
@Consume stat: StatInfo
build(){
Row(){
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
// 层叠容器
Stack(){
Progress({
value:this.StatInfo.finishTask,
total:this.StatInfo.totalTask,
type:ProgressType.Ring
})
.width(100)
Row(){
Text(this.finishTask.toString())
.fontColor('#36D')
.fontSize(24)
Text(' / '+this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({top:20,bottom:10})
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
@Consume stat: StatInfo
// 任务数组
@State tasks:Task[] = []
handleTaskChange(){
// 更新任务总数量
this.StatInfo.totalTask = this.tasks.length
// 更新已完成任务数量
this.StatInfo.finishTask = this.tasks.filter(item => item.finished).length
}
build(){
Column(){
// 新增任务按钮
Button('新增任务')
.width(200)
.onClick(()=>{
this.tasks.push(new Task())
// 更新任务总数量
// this.totalTask = this.tasks.length
this.handleTaskChange()
}).margin({bottom:10})
// 任务列表List版本
List({space:10}){
ForEach(
this.tasks,
(item:Task,index) =>{
ListItem(){
Row(){
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val=>{
// 更新当前任务状态
item.finished = val
// 更新已完成任务数量
// this.finishTask = this.tasks.filter(item => item.finished).length
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({end:this.DeleteButton(index)})
}
)
}
.width('100%')
.alignListItem(ListItemAlign.Center)
.layoutWeight(1)
}
}
@Builder DeleteButton(index: number){
Button(){
Image($r('app.media.ic_public_delete_filled'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(()=>{
this.tasks.splice(index,1)
this.handleTaskChange()
})
}
}
@ObjectLink和@Observed装饰器用于在涉及嵌套对象或数组元素为对象的场景中进行双向数据同步
页面路由是指在应用程序中实现不同页面之间的跳转和数据传递。
模式 | 作用 |
---|---|
router.pushUrl() | 目标页不会替换当前页,而是压入页面栈,因此可以用router.back()返回当前页 |
router.replaceUrl() | 目标页替换当前页,当前页会被销毁并释放资源,无法返回当前页 |
模式 | 作用 |
---|---|
Standard | 标准实例模式。每次跳转都会新建一个目标页并压入栈顶。默认模式。 |
single | 单实例模式。如果目标页已经存在栈中,则离栈顶最近的相同Url页面会被移动到栈顶并重新加载 |
使用步骤
1.导入组件,Router模块:
import router from '@ohos.router';
2.利用router实现跳转、返回等操作:
//跳转到指定路径,并传递参数
router.pushUrl(
{
url:'pages/ImagePage',//目标页面路径
params:{id:1}//传递参数(可选)
},
router.RouterMode.Single,//页面模式:RouterMode枚举
err => {
if(err){
//异常响应回调函数,错误码err.code:
//100001:内部错误,可能是渲染失败
//100002:路由地址错误
//100003:路由栈中页面超过32
console.log('路由失败.')
}
}
)
//获取传递过来的参数
params: any = router.getParams()
//返回上一页
router.back()
//返回到指定页,并携带参数
router.back(
{
url:'pages/Index',
params:{id:10}
}
)