本文章是根据黑马程序员鸿蒙 HarmonyOS NEXT星河版零基础入门到实战
该视频真的非常适合有点了解前端的小伙伴学习,里面有很多最基础的东西。
有前端经验,react经验的小伙伴看这个视频就非常的容易理解,直接看以下的笔记,认真过一遍就可以了。
以下是我的练习仓库:
HarmonyOS-learn: 对HarmonyOS的基础学习记录 (gitee.com)https://gitee.com/saro-d/harmonyOS-learn
后续将持续更新该视频的笔记
ArkTs
// 打印
console.log('你好,我第一次来','黑马');
// 变量
let firstDay:string = '他们吵起来了'
firstDay = '看视频吵起来的'
// 常量
const commoy:string ='这是个常量,不可修改'
// 数组
const names:string[] = ['小红','小明','笑话']
// 函数
function fn(val:number){
console.log('你好,我是函数', val)
}
fn(2)
// 箭头函数
const jianTouFn = (val:string)=>{
console.log('你好,我是箭头函数', val)
}
jianTouFn('箭头函数1')
// 对象
interface perObj{
name:string,
age:number,
statue:boolean,
sing:()=>void,
say:(val:string)=>string
}
const person:perObj = {
name:'大大',
age:18,
statue:false,
sing:() => {
console.log('唱歌了')
},
say:(val:string) => {
return val
}
}
person.sing()
console.log('对象名',person.name)
console.log('对象说话',person.say('你好'))
// 联合类型
let res:string | number |boolean = '优'
res = 100
res = false
let gender:'man'|'woman'|'no' = 'no' // 值已经被约束
// 枚举类型
enum ColorEnum{
Red='红色',
Black='黑色'
}
let sayColor:ColorEnum=ColorEnum.Red
console.log('颜色',sayColor)
ArkUI
组件:容器组件,基础组件
根组件只有一个,所以最外层需要用Column容器组件包裹
struct Index {
build() {
Column(){
Text('小说简介')
Row(){
Text('都市')
Text('言情')
Text('生活')
Text('男频')
}
}
}
}
组件字体属性方法
字体颜色
struct Index {
build() {
Column(){
Text('小说简介')
.margin(10)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Pink)
Row(){
Text('都市')
.fontSize(20)
.fontColor(Color.Green)
Text('言情')
.margin(10)
.fontColor(Color.White)
Text('生活')
.fontSize(20)
.margin(10)
.fontColor(Color.Blue)
Text('男频')
.fontColor(Color.White)
}
.margin(10)
}
.width('100%')
.backgroundColor('#afb1b3')
}
}
文字溢出省略号,行高
Column(){
Text('鸿蒙开发初体验')
.width('100%')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text('文字溢出省略号,行高文字溢出省略号,行高文字溢出省略号,行高文字溢出省略号,行高文字溢出省略号,行高')
.width('100%')
.textOverflow({
overflow:TextOverflow.Ellipsis
})
.maxLines(2)
.lineHeight(30)
}
图片组件使用
// 图片
Column(){
Row(){
Text('网络图片 ')
Image('https://www.itheima.com/images/logo.png')
.width(200)
}
Column(){
Image($r('app.media.Img01'))
.width(200)
.margin(20)
Row(){
Image($r('app.media.img02')).width(50) .margin(10)
Text('网络图片')
}
}
.margin(20)
.width('100%')
}
输入框和按钮
@Entry
@Component
struct inputBtn {
build() {
Column({space:20}){
TextInput({
placeholder:'请输入用户名'
})
TextInput({
placeholder:'请输入密码'
})
.type(InputType.Password)
Button('登录')
.width(100)
}
.width(300)
}
}
登录页面练习
@Entry
@Component
struct Login {
build() {
Column({space:20}){
Image($r('app.media.img02')).width(100)
Column({space:20}){
TextInput({
placeholder:'请输入用户名'
})
TextInput({
placeholder:'请输入密码'
})
.type(InputType.Password)
Button('登录')
.width('100%')
}
Row({space:20}){
Text('前往注册')
Text('忘记密码')
}
}.padding(20)
}
}
Svg图标
布局元素组成
内边距
外边距
边框
练习
@Entry
@Component
struct QQLogin {
@State user:string = '大王叫我来巡山'
build() {
Column(){
Image($r('app.media.img02')).width(100).borderRadius(50)
Text(this.user).margin({
top:20,
bottom:40
})
Column({space:15}){
Button('QQ登录')
.width('100%')
Button('微信登录')
.width('100%')
.backgroundColor('#dfdfdf')
.fontColor('#1e1e1e')
}
Row({space:20}){
Text('前往注册')
Text('忘记密码')
}.margin({
top:20
})
}.padding(20)
}
}
圆角
特殊形状圆角
背景属性
背景图
背景图位置
背景图单位
默认单位是px
背景图尺寸
线性布局
主轴对齐
交叉轴对齐
自适应伸缩
得物卡片
@Entry
@Component
struct DeWuCard {
build() {
Column(){
Image($r('app.media.img02'))
.width('100%')
.height(250)
.borderRadius({
topLeft:10,
topRight:10
})
Text('今晚吃这个 | 每日艺术分享')
.width('100%')
.padding({
top:20,
right:10,
left:10,
bottom:20
})
.fontSize(20)
.fontWeight(FontWeight.Bold)
Row(){
Image($r('app.media.img02'))
.width(25)
.margin({
right:5
})
Text('插画师分享聚集地')
.layoutWeight(1)
Image($r('app.media.img02'))
.width(25)
.margin({
right:5
})
Text('2300')
.width(40)
}
.margin(10)
}
.width(300)
.height(360)
.backgroundColor(Color.Pink)
.borderRadius(10)
}
}
京东登录案例
@Entry
@Component
struct JDLogin {
build() {
Column(){
Row(){
Image($r('app.media.cancel'))
.height(20)
Text('帮助')
}
.width('100%')
.height(30)
.justifyContent(FlexAlign.SpaceBetween)
Image($r('app.media.jdlogo'))
.width(200)
.margin({
top:50,
bottom:30
})
// 表单
Row(){
Text('国家/地址')
.fontColor('#666')
.height(16)
.layoutWeight(1)
Text('中国(+86)')
.fontColor('#666')
.height(16)
Image($r('app.media.ic_arrow_right'))
.fillColor('#666')
.height(16)
}
.backgroundColor('#fff')
.width('100%')
.padding(10)
.height(40)
.borderRadius(20)
Row(){
TextInput({
placeholder:'请输入手机号'
})
.placeholderColor('#666')
.height('100%')
.padding(0)
.backgroundColor('#fff')
}
.backgroundColor('#fff')
.width('100%')
.padding(10)
.height(40)
.borderRadius(20)
.margin({top:20,bottom:20})
// 条款
Row(){
Checkbox().width(10)
Text(){
Span('我已经阅读并同意')
Span('《京东隐私政策》《京东用户协议》')
.fontColor('#3274f6')
Span('未注册的手机号将自动创建京东账号')
}
.width('100%')
.fontSize(12)
.fontColor('#666')
}
.width('100%')
.margin({right:20,bottom:25})
.alignItems(VerticalAlign.Top)
Button('登录').width('100%').backgroundColor('#bf2838')
Row({space:25}){
Text('注册新用户')
.fontSize(14)
Text('账户密码登录')
.fontSize(14)
Text('无法登录')
.fontSize(14)
}
.margin({top:15})
// 其他
Blank()
Column(){
Text('其他登录方式')
.fontSize(14)
.height(22)
.fontColor('#666')
Row(){
Image($r('app.media.jd_huawei'))
.width(34)
Image($r('app.media.jd_wechat'))
.width(34)
Image($r('app.media.jd_weibo'))
.width(34)
Image($r('app.media.jd_QQ'))
.width(34)
}
.width('100%')
.padding(28)
.justifyContent(FlexAlign.SpaceBetween)
}
.height(100)
}
.padding(20)
.width('100%')
.height('100%')
.linearGradient({
angle:135,
direction:GradientDirection.RightBottom,
colors:[[0xb6d4d5,0.0],[0xebebeb,0.3],[0xf7e9e8,0.5],[0xffffff,1.0]]
})
}
}
弹性布局
例子
@Entry
@Component
struct Login {
build() {
Flex({
direction:FlexDirection.Column,
justifyContent:FlexAlign.Center,
alignItems:ItemAlign.Center
}){
Text().width(100).height(100).backgroundColor(Color.Pink).border({
width:1,
color:Color.Black })
Text().width(100).height(100).backgroundColor(Color.Pink).border({
width:1,
color:Color.Black })
Text().width(100).height(100).backgroundColor(Color.Pink).border({
width:1,
color:Color.Black })
}.width('100%').height(600).backgroundColor(Color.Green)
}
}
换行
Grid布局
例子:
间隙:
角标组件Badge
绝对定位和zIndex层级
@Entry
@Component
struct JDLogin {
build() {
Column(){
Text().width(100).height(100).backgroundColor(Color.Yellow).border({
width:1,
color:Color.Black })
.position({
x:50,
y:100
})
.zIndex(-1)
}
}
}
层叠布局
B站卡片案例
@Entry
@Component
struct Login {
build() {
Column(){
Column(){
Stack({alignContent:Alignment.Bottom}){
Image($r('app.media.img02')).width('100%').height('100%')
.borderRadius({topLeft:20,topRight:20})
Row(){
Row({space:5}){
Image($r('app.media.jd_wechat')).width(16)
Text('288万').fontColor(Color.White)
}.margin({right:10})
Row({space:5}){
Image($r('app.media.jd_wechat')).width(16)
Text('288万').fontColor(Color.White)
}.layoutWeight(1)
// 除了写.layoutWeight(1),也可以写
// Blank()
Text('4:33').fontColor(Color.White)
}.width('100%').height(30).alignItems(VerticalAlign.Center).padding({right:5,left:5})
}.width(300).height(160)
// 文字
Text('【凤凰传奇新歌】欧迎来到国风统治区:唢呐一响神曲《铁衣【凤凰传奇新歌】欧迎来到国风统治区:唢呐一响神曲《铁衣')
.lineHeight(20).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(2)
.padding(10)
Row(){
Text('19万点赞').backgroundColor('#fff1f0').fontColor('#c77a60').padding(5)
Image($r('app.media.jd_wechat')).width(16).margin({right:5})
}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding(10)
}.width(300).height(270).borderRadius(20).backgroundColor(Color.White)
}.width('100%').height('100%').backgroundColor('#f6f8fa')
}
}
阶段综合-支付宝首页
@Entry
@Component
struct ZfbHome {
build() {
Stack({alignContent:Alignment.Bottom}){
Stack({alignContent:Alignment.Top}){
// 顶部搜索
Row(){
Column(){
Row(){
Text('重庆').fontColor(Color.White)
Image($r('app.media.top_down')).width(20).fillColor(Color.White)
}
Text('晴 2℃').fontColor(Color.White).fontSize(14)
}.height(33).alignItems(HorizontalAlign.Start)
Row(){
Image($r('app.media.top_sousuo')).width(20)
TextInput({
placeholder:'重庆交通一卡通'
}).placeholderColor('#666').layoutWeight(1)
Text('搜索').fontColor('#4c74ef').width(55).border({ width:{left:1},color:'#e9e9e9'}).textAlign(TextAlign.Center)
}.height(33).backgroundColor(Color.White).borderRadius(10)
.margin({left:12,right:12}).padding({left:10,right:10}).layoutWeight(1)
Image($r('app.media.top_add')).width(30).fillColor(Color.White)
}.width('100%').height(60).padding({left:10,right:10})
.backgroundColor('#6681ea').zIndex(2)
// 内容
Scroll(){
Column(){
Row(){
Column(){
Image($r('app.media.head_sao')).width(28)
Text('扫一扫').fontColor(Color.White)
}
Column(){
Image($r('app.media.head_shoufukuan')).width(28)
Text('收付款').fontColor(Color.White)
}
Column(){
Image($r('app.media.head_chuxing')).width(28)
Text('出行').fontColor(Color.White)
}
Column(){
Image($r('app.media.head_car')).width(28)
Text('卡包').fontColor(Color.White)
}
}.width('100%').margin({bottom:20})
.justifyContent(FlexAlign.SpaceAround).alignItems(VerticalAlign.Center)
Column(){
// 多功能
Flex({
direction:FlexDirection.Row,
justifyContent:FlexAlign.SpaceAround,
alignContent:FlexAlign.SpaceAround,
wrap:FlexWrap.Wrap
})
{
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
Column(){
Image($r('app.media.dd')).width(28)
Text('滴滴')
}.width('20%')
}.width('100%').height(170)
.backgroundColor(Color.White).borderRadius({topLeft:20,topRight:20})
// 推荐
Row(){
Column(){
Stack({alignContent:Alignment.Top}){
Text().width('100%').height(40).backgroundColor('#fde5ff')
Text('官方收钱码').padding(6).fontColor('#d6b5d9').fontSize(12).fontWeight(600)
.backgroundColor('#FFF').borderRadius({bottomRight:10,bottomLeft:10})
}
Column(){
Text('收钱码站出来').fontWeight(700).fontColor('#af6ac6').fontSize(15)
Text('最高100元奖励').fontColor('#d6b5d9').fontSize(14)
Image($r('app.media.shouju')).height(80).position({y:50,x:10})
}.layoutWeight(1)
}.height('100%').width(110).borderRadius(10).backgroundColor(Color.White)
Column(){
Row({space:2})
{
Image($r('app.media.jd_huawei')).width(20)
Text('消费圈').fontWeight(600)
Text('便宜').padding(4).linearGradient({
angle:90,
direction:GradientDirection.Right,
colors:[[0xd79b5e,0.0],[0xda5e7a,1.0]]
}).borderRadius(10).fontColor(Color.White).fontSize(11)
}.width('100%').height(40).linearGradient({
angle:90,
direction:GradientDirection.Right,
colors:[[0xfde3d2,0.0],[0xfdeee5,1.0]]
})
Image($r('app.media.img02')).width(80).margin({top:12,bottom:15})
Row(){
Image($r('app.media.jd_wechat')).width(30)
Column(){
Text('买绿色商品').fontSize(13).fontWeight(600)
Text('得森林能量').fontSize(13).fontColor('#b5b5b5')
}
}
}.height('100%').width(110).borderRadius(10).backgroundColor(Color.White)
Column(){
Row({space:2})
{
Image($r('app.media.jd_huawei')).width(20)
Text('理好财').fontWeight(600)
Text('精选').padding(4).linearGradient({
angle:90,
direction:GradientDirection.Right,
colors:[[0xd79b5e,0.0],[0xda5e7a,1.0]]
}).borderRadius(10).fontColor(Color.White).fontSize(11)
}.width('100%').height(40).linearGradient({
angle:90,
direction:GradientDirection.Right,
colors:[[0xd5e6fe,0.0],[0xe7efff,1.0]]
})
Image($r('app.media.img02')).width(80).margin({top:12,bottom:15})
Row(){
Image($r('app.media.jd_wechat')).width(30)
Column(){
Text('买绿色商品').fontSize(13).fontWeight(600)
Text('得森林能量').fontSize(13).fontColor('#b5b5b5')
}
}
}.height('100%').width(110).borderRadius(10).backgroundColor(Color.White)
}.width('100%').height(160).justifyContent(FlexAlign.SpaceAround).margin({top:10})
// 视频
Row(){
Column(){
Row({space:10}){
Image($r('app.media.dd')).width(25)
Text('市民中心·城市发布').fontWeight(700)
}.width('100%').margin({bottom:10})
Text('在重庆退休后能领多少养老金?').font({
size:14,
weight:600
}).lineHeight(20)
Row({space:20}){
Text('怎样计算?').fontSize(14).fontColor('#c1c1c1')
Text('政务办事').fontSize(14).padding(2).backgroundColor('#f9eccf').fontColor('#c88757')
}.margin({bottom:20})
Text('去看看').fontSize(16).fontWeight(600).padding(10)
.backgroundColor('#f9eccf').fontColor('#c88757').borderRadius(10)
}.layoutWeight(1).alignItems(HorizontalAlign.Start)
Stack({
alignContent:Alignment.TopStart
})
{
Image($r('app.media.Img01')).borderRadius(10)
Image($r('app.media.play')).width(30)
}.width(130)
}.width('100%').height(160).padding(10).margin({top:20,bottom:20}).backgroundColor(Color.White)
// 消费圈
Flex(){}
}.width('100%').backgroundColor('#f8f8f8').borderRadius({topLeft:20,topRight:20})
}.width('100%').padding({top:60,bottom:60})
.backgroundColor('#6681ea')
}
}
// 底部Tab
Row(){
Column(){
Image($r('app.media.tab_zfb')).width(40)
}
Column(){
Image($r('app.media.tab_licai')).width(28)
Text('理财')
}
Column(){
Image($r('app.media.tab_life')).width(28)
Text('生活')
}
Column(){
Image($r('app.media.tab_xiaoxi')).width(28)
Text('消息')
}
Column(){
Image($r('app.media.tab_i')).width(28)
Text('我的')
}
}.width('100%').height(60).backgroundColor(Color.White)
.justifyContent(FlexAlign.SpaceAround).alignItems(VerticalAlign.Center)
}.width('100%').height('100%').backgroundColor(Color.Pink)
}
}
字符串拼接
模板字符串
类型转换(数字和字符串)
字符串转数字
数字转字符串
交互
点击事件
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column(){
Button('点击喔')
.onClick(()=>{
AlertDialog.show({
message:'你好~这是个弹窗'
})
})
}
}
}
状态管理
// 普通变量
let msg:string='我是组件外普通变量'
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
msg1:string='我是组件内普通变量'
msg2:string='我是组件内普通变量2'
build() {
Column(){
Text(msg)
Text(this.msg1)
Button(this.message)
.onClick(()=>{
AlertDialog.show({
message:'你好~这是个弹窗'
})
this.message = '已经点击了'
})
}
}
}
计算器案例
@Entry
@Component
struct CounterPage{
@State num:number = 0
build() {
Row({space:10}){
Button('-')
.onClick(()=>{
this.num--
})
Text(this.num.toString())
Button('+')
.onClick(()=>{
this.num++
})
}
}
}
运算符
算数运算符
赋值运算符
点赞案例
@Entry
@Component
struct CounterPage{
@State count:number=999
@State supportColor:string =''
@State supportState:boolean = false
build() {
Column({space:10}){
// 爱心
Row({space:10}){
Image($r('app.media.love')).width(30).fillColor(this.supportColor)
Text(this.count.toString()).fontColor(this.supportColor)
}
.onClick(()=>{
if(this.supportState){
this.supportColor = ''
this.count --
this.supportState = false
}else{
this.supportColor = '#8f1422'
this.count ++
this.supportState = true
}
})
}
}
}
一元运算符
比较运算符
逻辑运算符
运算符优先级
美团购物车案例
@Entry
@Component
struct ShoppingCart{
// 原价
@State priced:number=30
// 单价
@State unitPrice:number=20.2
// 数量
@State quantity:number=0
// 总价
@State allPrice:number=0
// 优惠
@State preferential:number=0
build() {
Stack({
alignContent:Alignment.Bottom
})
{
// 商品列表
Column(){
Row({space:5}){
Image($r('app.media.img02')).width(110).borderRadius(10)
Column({space:6}){
Text('冲销量1000ml缤纷八果水果捞').width('100%').font({size:14,weight:600})
Text('含1份折扣商品').width('100%').font({size:12}).fontColor('#8c8c8c')
Blank()
Row(){
Text(`¥${this.unitPrice}`).fontColor('#bd342a')
Text(`¥${this.priced}`).font({size:12}).fontColor('#8c8c8c').decoration({type:TextDecorationType.LineThrough}).margin({left:5})
Blank()
Row(){
Text('-').width(20).height('100%').border({width:1,color:'#979797'}).textAlign(TextAlign.Center).fontWeight(600).borderRadius({topLeft:5,bottomLeft:5})
.onClick(()=>{
if(this.quantity == 0) return
this.quantity --
this.allPrice = this.quantity * this.unitPrice
this.preferential = this.quantity * (this.priced - this.unitPrice)
})
Text(this.quantity.toString()).layoutWeight(1).height('100%').border({width:{top:1,bottom:1},color:'#979797'}).textAlign(TextAlign.Center).fontWeight(600)
Text('+').width(20).height('100%').border({width:1,color:'#979797'}).textAlign(TextAlign.Center).fontWeight(600).borderRadius({topRight:5,bottomRight:5})
.onClick(()=>{
this.quantity ++
this.allPrice = this.quantity * this.unitPrice
this.preferential = this.quantity * (this.priced - this.unitPrice)
})
}.width(75).height(25)
}.width('100%')
}.layoutWeight(1).height('100%')
}.height(83).width('100%')
}.width('100%').height('100%').padding(10)
// 结算
Row({space:10}){
Column(){
Text(){
Span(`已选 ${this.quantity} 件,`).fontColor('#919191')
Span('合计:')
Span(`¥${this.allPrice.toFixed(2)}`).fontColor('#bd342a')
}.fontSize(14)
Text(`共减¥${this.preferential.toFixed(2)}`).fontColor('#bd342a').fontSize(12)
}.layoutWeight(1).alignItems(HorizontalAlign.End)
Text('结算外卖').width(100).height(40).backgroundColor('#ffd441').font({size:17,weight:600}).textAlign(TextAlign.Center).borderRadius(20)
}.width('100%').height(100).backgroundColor(Color.White).padding(20)
}.backgroundColor('#f3f3f3').width('100%').height('100%')
}
}
数组操作
语句
if分支语句
if多分支
switch分支
三元条件表达式
条件渲染
条件渲染案例
@Entry
@Component
struct JDAddCart {
// 库存状态
@State inventoryStatus:boolean = true
build() {
Column(){
if(this.inventoryStatus){
Text('还有一件商品')
}else {
Text('没有商品')
}
Row(){
Column(){
Image($r('app.media.love')).width(28)
Text('店铺')
}
Column(){
Image($r('app.media.love')).width(28)
Text('店铺')
}
Column(){
Image($r('app.media.love')).width(28)
Text('店铺')
}
if(this.inventoryStatus){
Text('加入购物车').width(100).height('100%').backgroundColor('#ffc73e').fontColor(Color.White).borderRadius(20).textAlign(TextAlign.Center)
Text('立即购买').width(100).height('100%').backgroundColor('#fa0028').fontColor(Color.White).borderRadius(20).textAlign(TextAlign.Center)
}else {
Text('查看类似商品').width(170).height('100%').backgroundColor('#ffc73e').fontColor(Color.White).borderRadius(20).textAlign(TextAlign.Center)
}
}.width('100%').height(60).justifyContent(FlexAlign.SpaceAround)
Button('切换').onClick(()=>{
this.inventoryStatus = !this.inventoryStatus
})
}
}
}
循环语句
while循环
for循环
退出循环
遍历数组
for()
for...of
对象数组
ForEach-渲染控制
interface Article{
title:string,
createTime:string
}
@Entry
@Component
struct JDAddCart {
@State articles:Article[]=[
{
title:'近200+自动驾驶数据集全面调研!一览如何数据闭环全流程',
createTime:'2024-01-31 09:59:43'
},
{
title:'MySQL Shell 8.0.32 for GreatsQL编译二进制包',
createTime:'2024-01-31 09:55:53'
},
{
title:'在Redis中如何实现分布式事务的一致性?',
createTime:'2024-01-31 09:54:51'
},
]
build() {
Column(){
Column({space:20}){
ForEach(this.articles,(item:Article,index)=>{
Column({space:10}){
Text(item.title).fontSize(16).fontWeight(600).width('100%')
Text(item.createTime).fontSize(12).fontColor('#cdcdcd').width('100%')
}.width('100%').border({width:{bottom:2},color:'#cdcdcd'}).padding(10)
})
}.width('100%')
}
}
}
生肖卡抽奖案例
import { JSON } from '@kit.ArkTS'
interface ZodiacCardItem{
url:string,
activeUrl:string,
count:number
}
// const t:number = Math.floor(Math.random() *6)
// console.log( '随机树:',t)
@Entry
@Component
struct ZodiacDraw {
// 卡片数据
@State zodiacCards:ZodiacCardItem[] = [
{ url:'app.media.dog',activeUrl:'app.media.active_dog',count:1},
{ url:'app.media.hu',activeUrl:'app.media.active_hu',count:1},
{ url:'app.media.long',activeUrl:'app.media.active_long',count:1},
{ url:'app.media.ma',activeUrl:'app.media.active_ma',count:0},
{ url:'app.media.niu',activeUrl:'app.media.active_niu',count:1},
{ url:'app.media.tu',activeUrl:'app.media.active_tu',count:1}
]
// 页面层次
@State takePagezIndex:number = -1
@State takePageOpacity:number = 0
@State phoneStatus:boolean = true
// 抽中下标
@State drawnIndex:number = -1
// 抽中动画
@State drawnScale:number = 0
// 中奖奖池
@State prizePools:string[] = ['phone','huawei','xiaomi']
@State prize:string = ''
build() {
Stack(){
// 抽奖页
Column(){
Grid(){
ForEach(this.zodiacCards,(item:ZodiacCardItem,index)=>{
GridItem(){
Badge({
count:item.count,
position:BadgePosition.RightTop,
style:{
fontSize:14,
badgeSize:20,
badgeColor:'#fa2a2d'
}
})
{
// 如果count不为0,就渲染激活图片
Image($r(`${item.count == 0 ? item.url : item.activeUrl}`))
.width(90).border({width:{left:1,bottom:1},color:'#ffd4d4d4'})
}
}
})
}
.width('100%').height(300)
.margin({top:60,bottom:50})
.columnsTemplate('1fr 1fr 1fr').rowsTemplate('1fr 1fr')
Button('立即抽卡')
.backgroundColor('#ed4481').width(300)
.onClick(()=>{
// 结果页出
this.takePagezIndex = 1
this.takePageOpacity = 1
// 动画
this.drawnScale =1
// 结果卡片 随机
this.drawnIndex = Math.floor(Math.random() *6)
})
}
// 抽奖结果页
Column({space:25}){
Text('获得生肖卡').fontColor('#fff').fontSize(20)
Image($r(`${this.drawnIndex !==-1?this.zodiacCards[this.drawnIndex].activeUrl:null}`))
.width(140).borderRadius(20)
.scale({x:this.drawnScale,y:this.drawnScale}).animation({duration:500})
Button('开心收下')
.width(140).backgroundColor('#00000000').border({width:1,color:'#fff'})
.onClick(()=>{
// 结果页出
this.takePagezIndex = -1
this.takePageOpacity = 0
// 结果卡片
// 处理数组数据,对象数组的情况需要更新,就得修改整个对象
this.zodiacCards[this.drawnIndex] = {
url:this.zodiacCards[this.drawnIndex].url,
activeUrl:this.zodiacCards[this.drawnIndex].activeUrl,
count:this.zodiacCards[this.drawnIndex].count + 1
}
// 判断是否集齐卡片
this.phoneStatus = this.zodiacCards.some((item)=>item.count == 0)
// 判断方法2
// let flag:boolean=true
// for (let item of this.zodiacCards){
// if(item.count ==0){
// flag = false
// break
// }
// }
// 如果集齐
if(!this.phoneStatus){
const randomIndex = Math.floor(Math.random() * 3)
this.prize = this.prizePools[randomIndex]
}
})
}
.width('100%').height('100%')
.backgroundColor('#bc000000')
.justifyContent(FlexAlign.Center)
.zIndex(this.takePagezIndex)
.opacity(this.takePageOpacity)
.animation({duration:300})
// 手机页
if(!this.phoneStatus){
Column({space:25}){
Text('恭喜获得手机一部').fontColor('#fff').fontSize(20)
Image($r(`app.media.${this.prize}`))
.width(300).borderRadius(20)
.scale({x:this.drawnScale,y:this.drawnScale}).animation({duration:500})
Button('再来一次')
.width(140).backgroundColor('#00000000').border({width:1,color:'#fff'})
.onClick(()=>{
// 将之前卡片所有数量-1
// let arr:ZodiacCardItem[] =[]
// this.zodiacCards.forEach((item:ZodiacCardItem)=>{
// let obj:ZodiacCardItem = {
// url: item.url,
// activeUrl: item.activeUrl,
// count: item.count - 1
// }
// arr.push(obj)
// })
// this.zodiacCards= arr
// 方法2
this.zodiacCards = this.zodiacCards.map((item: ZodiacCardItem) => ({
url: item.url,
activeUrl: item.activeUrl,
count: item.count - 1
}) as ZodiacCardItem)
this.phoneStatus = true
})
}
.width('100%').height('100%')
.backgroundColor('#bc000000')
.justifyContent(FlexAlign.Center)
.animation({duration:300})
}
}
}
}
swiper轮播组件
基本用法
需要给swiper设置尺寸,若不设置则是内容自动撑开,也可以给内容每个单独设置。
@Entry
@Component
struct SwiperPage {
build() {
Column(){
Swiper(){
Text('你好').backgroundColor(Color.Blue)
Text('我是').backgroundColor(Color.Gray)
Text('大大').backgroundColor(Color.Green)
}.width('100%').height(150)
Swiper(){
Image($r('app.media.active_niu'))
Image($r('app.media.active_ma'))
Image($r('app.media.active_long'))
Image($r('app.media.active_hu'))
}.width(150).height(200).margin({top:20}).border({width:1})
}
}
}
常见属性
@Entry
@Component
struct SwiperPage {
build() {
Column(){
Swiper(){
Text('你好').backgroundColor(Color.Blue)
Text('我是').backgroundColor(Color.Gray)
Text('大大').backgroundColor(Color.Green)
}.width('100%').height(150)
.loop(true)
.autoPlay(true)
.interval(2000)
Swiper(){
Image($r('app.media.active_niu'))
Image($r('app.media.active_ma'))
Image($r('app.media.active_long'))
Image($r('app.media.active_hu'))
}.width('100%').height(400).margin({top:20}).border({width:1})
.loop(true)
.autoPlay(true)
.interval(3000)
.vertical(true)
}
}
}
样式自定义
aspectRatio()宽高比属性,设置和图片一致的宽高比,保证图片正常适配
代码演示
@Entry
@Component
struct SwiperPage {
build() {
Column(){
Swiper(){
Image($r('app.media.active_niu'))
Image($r('app.media.active_ma'))
Image($r('app.media.active_long'))
Image($r('app.media.active_hu'))
}.width('100%').aspectRatio(0.85).margin({top:20}).border({width:1})
.loop(true)
.autoPlay(true)
.interval(4000)
.indicator(
Indicator.dot()
.itemWidth(10)
.selectedItemWidth(30)
.selectedColor(Color.Green)
)
}
}
}
样式&结构的重用
@Extend:扩展组件(样式,事件)【侧重组件】
@Extend(扩展组件) Extend的参数是需要扩展的组件如Text,Column等
适用特定组件 样式、事件
@Extend(Text)
function txtFn (){
.fontSize(20)
.fontWeight(FontWeight.Bolder)
.margin({bottom:20})
}
@Extend(Text)
function swiperTxtFn (bgColor:ResourceColor,msg:string) {
.textAlign(TextAlign.Center)
.fontSize(20)
.fontWeight(FontWeight.Bolder)
.fontColor(Color.White)
.backgroundColor(bgColor)
.onClick(()=>{
AlertDialog.show({
message:msg
})
})
}
@Entry
@Component
struct ExtendPage {
build() {
Column(){
Text('@Extend:扩展组件(样式,事件)').txtFn()
Swiper(){
Text('你好').swiperTxtFn(Color.Gray,'你好轮播')
Text('我是').swiperTxtFn(Color.Green,'我是轮播')
Text('大大').swiperTxtFn(Color.Red,'轮播大大')
}.width('100%').height(150)
.loop(true)
.autoPlay(true)
.interval(2000)
}
}
}
@Styles:抽取通用属性,事件【侧重样式】
@Styles不支持传参,最好写组件内
适用公共样式、事件,不可以传参
// 全局定义style
@Styles function commonStyles (){
.width(100)
.height(100)
}
@Entry
@Component
struct StylePage {
@State bgColor:ResourceColor = Color.Gray
// 组件内定义style
@Styles setBg (){
.backgroundColor(this.bgColor)
.onClick(()=>{
this.bgColor = Color.Green
})
}
build() {
Column({space:20}){
Text('@Styles').commonStyles().setBg().fontColor(Color.White)
Text().commonStyles().setBg()
Text().commonStyles().borderRadius(50).setBg()
}.width('100%').justifyContent(FlexAlign.Center)
}
}
@Builder:自定义构建函数(结构,样式,事件)【侧重结构】
全局定义的函数在使用时不用写this,组件内定义的在使用时要写this
// 全局定义
@Builder
function navItem (icon:ResourceStr,txt:string){
Column({space:10}){
Image(icon).width(70).height(70)
Text(txt)
}.onClick(()=>{
AlertDialog.show({
message:'这里是' + txt
})
})
}
@Entry
@Component
struct BuilderPage {
// 组件内定义
@Builder
navItem (icon:ResourceStr,txt:string){
Column({space:10}){
Image(icon).width(70).height(70)
Text(txt)
}.onClick(()=>{
AlertDialog.show({
message:'这里是' + txt + ' @Builder'
})
})
}
build() {
Row({space:20})
{
navItem($r('app.media.yaodiao'),'阿里药店')
navItem($r('app.media.paimai'),'阿里拍卖')
this.navItem($r('app.media.nongchang'),'阿里农场')
this.navItem($r('app.media.yizhan'),'菜鸟驿站')
}.width('100%').justifyContent(FlexAlign.Center)
}
}
滚动容器Scroll
核心用法
@Entry
@Component
struct ScrollPage {
build() {
Scroll(){
Column({space:10}){
ForEach(Array.from({length:10}),(item:string,index)=>{
Text(`测试文本${index + 1}`)
.width('100%').height(50)
.fontColor(Color.White)
.backgroundColor(Color.Orange)
.textAlign(TextAlign.Center)
})
}.width('100%').padding(10)
}.width('100%').height(400)
}
}
常见属性
@Entry
@Component
struct ScrollPage {
build() {
Scroll(){
Column({space:10}){
ForEach(Array.from({length:10}),(item:string,index)=>{
Text(`测试文本${index + 1}`)
.width('100%').height(50)
.fontColor(Color.White)
.backgroundColor(Color.Orange)
.textAlign(TextAlign.Center)
})
}
.width('100%').padding(10)
}
.width('100%').height(400)
.scrollable(ScrollDirection.Vertical) // 滚动方向
.scrollBar(BarState.Auto) // On 一直显示,Off一直隐藏 Auto滑动显示
.scrollBarWidth(5) // 滚动条宽度
.edgeEffect(EdgeEffect.Spring) // 滑动效果
.scrollBarColor(Color.Green)
}
}
控制器
@Entry
@Component
struct ScrollPage {
// 1.创建Scroll 对象(实例化)
myScroll:Scroller = new Scroller()
build() {
Column(){
// 2.绑定给Scroll组件
Scroll(this.myScroll){
Column({space:10}){
ForEach(Array.from({length:10}),(item:string,index)=>{
Text(`测试文本${index + 1}`)
.width('100%').height(50)
.fontColor(Color.White)
.backgroundColor(Color.Orange)
.textAlign(TextAlign.Center)
})
}
.width('100%').padding(10)
}
.width('100%').height(400).margin({bottom:50})
.scrollable(ScrollDirection.Vertical) // 滚动方向
.scrollBar(BarState.Auto) // On 一直显示,Off一直隐藏 Auto滑动显示
.scrollBarWidth(5) // 滚动条宽度
.edgeEffect(EdgeEffect.Spring) // 滑动效果
.scrollBarColor(Color.Green)
Button('回到顶部/底部')
.onClick(()=>{
this.myScroll.scrollEdge(Edge.Bottom) // Edge.Top Edge.Start回到顶部
})
Button('获取滚动位置').margin(20)
.onClick(()=>{
const y = this.myScroll.currentOffset().yOffset
AlertDialog.show({
message:`y:${y}`
})
})
}
}
}
事件
返回顶部案例
@Entry
@Component
struct ScrollPage {
// 1.创建Scroll 对象(实例化)
myScroll:Scroller = new Scroller()
// 距离顶部位置
@State scrollTop:number = 0
build() {
// 淘宝滚动案例
Column(){
Scroll(this.myScroll){
Column(){
Image($r('app.media.t_b'))
}
}.width('100%')
.height('100%')
.onScroll((x,y)=>{
this.scrollTop = this.myScroll.currentOffset().yOffset
// console.log('x,y',x,y,this.scrollTop)
})
if( this.scrollTop >= 200){
Row(){
Image($r("app.media.rocket")) .width(50)
}
.position({bottom:30,right:20})
.backgroundColor(Color.White)
.borderRadius(25)
.onClick(()=>{
this.myScroll.scrollEdge(Edge.Top)
})
}
}
}
}
列表组件list
字体图标
容器组件Tabs
基本用法
@Entry
@Component
struct TabsPage {
build() {
Tabs(){
TabContent(){ // 有且只能有一个子组件
Text('首页内容')
}
.tabBar('首页') // 配置导航 也可以不配
TabContent(){ // 有且只能有一个子组件
Text('推荐内容')
}
.tabBar('推荐')
TabContent(){ // 有且只能有一个子组件
Text('我的内容')
}
.tabBar('我的')
}
}
}
常用属性
滚动导航栏
@Entry
@Component
struct TabsPage {
@State titles:string[] = [
'首页','关注','热门','军事','体育',
'八卦','数码','财经','美食','旅行'
]
build() {
Tabs(){
ForEach(this.titles,(item:string,index)=>{
TabContent(){ // 有且只能有一个子组件
Text(`${item}内容`)
}
.tabBar(item) // 配置导航 也可以不配
})
}
.barMode(BarMode.Scrollable)
}
}
自定义TaBar
切换高亮
interface Item{
title:string,
icon:ResourceStr
}
@Entry
@Component
struct TabsPage {
@State tabList:Item[] = [
{
title:'首页',
icon:$r('app.media.home')
},
{
title:'推荐',
icon: $r('app.media.tuijian')
},
{
title:'新增',
icon:$r('app.media.add')
},
{
title:'我的',
icon:$r('app.media.my')
},
]
// 选择tab
@State selectTabIndex:number = 0
// 构建tab
@Builder
myTabBuilder(itemIndex:number,icon:ResourceStr,title:string){
Column({space:8}){
Image(icon).width(30).fillColor(`${this.selectTabIndex == itemIndex ? Color.Orange:Color.Black}`)
Text(title).fontColor(`${this.selectTabIndex == itemIndex ? Color.Orange:Color.Black}`)
}
}
build() {
// 切换高亮
Tabs({barPosition:BarPosition.End}){
ForEach(this.tabList,(item:Item,index)=>{
TabContent(){ // 有且只能有一个子组件
Text(`${item.title}内容`)
}
.tabBar(this.myTabBuilder(index,item.icon,item.title)) // 配置导航 也可以不配
})
}.onChange((index)=>{
this.selectTabIndex = index
})
}
}
案例:小米有品底部Tabs
interface Item{
title:string,
icon:ResourceStr
}
@Entry
@Component
struct TabsPage {
@State tabList:Item[] = [
{
title:'首页',
icon:$r('app.media.home')
},
{
title:'推荐',
icon: $r('app.media.tuijian')
},
{
title:'推买',
icon: $r('app.media.yizhan')
},
{
title:'新增',
icon:$r('app.media.add')
},
{
title:'我的',
icon:$r('app.media.my')
},
]
// 选择tab
@State selectTabIndex:number = 0
// 构建tab
@Builder
myTabBuilder(itemIndex:number,icon:ResourceStr,title:string){
Column({space:8}){
Image(icon).width(28).fillColor(`${this.selectTabIndex == itemIndex ? Color.Orange:Color.Black}`)
Text(title).fontColor(`${this.selectTabIndex == itemIndex ? Color.Orange:Color.Black}`)
}
}
// 构建中间的tab
@Builder
centerTabBuilder(icon:ResourceStr){
Image(icon).width(50)
}
build() {
// 切换高亮
Tabs({barPosition:BarPosition.End}){
ForEach(this.tabList,(item:Item,index)=>{
if(index == 2){
TabContent(){ // 有且只能有一个子组件
Text(`${item.title}内容`)
}
.tabBar(this.centerTabBuilder(item.icon))
}else {
TabContent(){ // 有且只能有一个子组件
Text(`${item.title}内容`)
}
.tabBar(this.myTabBuilder(index,item.icon,item.title)) // 配置导航 也可以不配
}
})
}.onChange((index)=>{
this.selectTabIndex = index
})
}
}
Class类
Class类 实例属性
// 实例对象
class Cat{
name:string = '小十'
food?:string
}
let catObj = new Cat()
catObj.food = '鸡肉猫条'
console.log('名字:',catObj.name)
console.log('食物:',catObj.food)
@Entry
@Component
struct classPage {
build(){}
}
Class类 构造函数
不同的实例,将来需要有不同的字段初始值,就需要通过构造函数实现
// ---------------------构造函数---------------------
interface CatObj{
food:string
age:number
}
class Cat{
name:string = '小十'
food?:string
age?:number
constructor(paramsObj:CatObj) {
// this.name = name
this.food = paramsObj.food
this.age = paramsObj.age
}
}
let catDay1 = new Cat({food:'鸡肉猫条',age:90})
console.log(`第 ${catDay1.age} 天吃:${catDay1.food}`)
let catDay2 = new Cat({food:'金枪🐟猫条',age:91})
console.log(`第 ${catDay2.age} 天吃:${catDay2.food}`)
@Entry
@Component
struct classPage {
build(){}
}
Class类 定义方法
类中可以定义方法,并且编写逻辑
// ---------------------定义方法-----------------------
interface CatObj{
food:string
age:number
}
class Cat{
name:string = '小十'
food?:string
age?:number
constructor(paramsObj:CatObj) {
// this.name = name
this.food = paramsObj.food
this.age = paramsObj.age
}
sayHi(yourName:string){
console.log(`你好! ${yourName} 我是${this.name}`)
}
}
let cat1 = new Cat({food:'鸡肉猫条',age:90})
cat1.sayHi('老大')
@Entry
@Component
struct classPage {
build(){}
}
静态属性 和 静态方法
类还可以添加静态属性,方法,后续访问需要通过类来完成。
// ---------------静态属性和方法----------------
class Person{
name:string = '小十'
food?:string
age?:number
constructor(paramsObj:CatObj) {
// this.name = name
this.food = paramsObj.food
this.age = paramsObj.age
}
sayHi(yourName:string){
console.log(`你好! ${yourName} 我是${this.name}`)
}
static secret:string ='我一天吃十吨'
static sing(){
console.log('我说:我唱歌难听')
}
}
const secret = Person.secret
console.log(Person.secret)
console.log('我的秘密:',secret)
Person.sing()
@Entry
@Component
struct classPage {
build(){}
}
继承 extends 和 super 关键字
类可以通过继承快速获取另一个类的字段和方法。
子类通过super可以访问父类的实例字段,实例方法和构造函数
// --------------------继承 extends 和 super 关键字--------------
class Person{
name:string = '小十'
food?:string
age?:number
constructor(paramsObj:CatObj) {
// this.name = name
this.food = paramsObj.food
this.age = paramsObj.age
}
sayHi(yourName:string){
console.log(`你好! ${yourName} 我是${this.name}`)
}
static secret:string ='我一天吃十吨'
static sing(){
console.log('我说:我唱歌难听')
}
}
class Student extends Person{
name:string = '李华' // 和父类属性名一样,重赋值会覆盖父类的值
grade?:string
constructor(paramsObj:CatObj,grade:string) {
// 父类中的构造函数,此时我们需要手动调用,super()构造函数,super.方法名(),super.属性名,
super(paramsObj)
// 完成自己属性的初始化
this.grade = grade
}
// 和父类属性名一样,重赋值会覆盖父类的值
sayHi(yourName:string){
super.sayHi(yourName) // 调用了父类的方法
console.log(`你好!我是${this.name}`) // 扩展了自己的特性
}
}
let student1 = new Student({food:'米饭',age:18},'五年级')
console.log('学生的名字:',student1.name)
student1.sayHi('student1')
class Teacher extends Person{}
let teacher1 = new Teacher({food:'米饭',age:28})
console.log('老师的名字:',teacher1.name)// 没有改变父类的name,打印出的name是父类定义的
teacher1.sayHi('teacher1')
class Mom extends Person{}
@Entry
@Component
struct classPage {
build(){}
}
instanceof 检测是否实例
// ---------------------------判断类型----------------
console.log(typeof 111)
console.log(typeof true)
console.log(typeof 'abc')
// typeof 仅能用于判断简单类型,复杂类型需要用instanceQf判断
class Person2 {}
class Student2 {}
let p:Person2 = new Person2()
let s: Student2 = new Student2()
console.log(typeof p)
console.log(typeof s)
class Person3 {}
class Student3 extends Person3 {}
class Worker extends Person3 {}
let m: Student3 = new Student3()
console.log('判断结尔:',m instanceof Student3)
console.log('判断结果:',m instanceof Person3)
console.log('判断结果:',m instanceof Worker)
@Entry
@Component
struct classPage {
build(){}
}
修饰符(readonly、private ..)
readonly
private
protected
public
// ---------------------修饰符----------------
//修饰符 readonly
class Cat2 {
name: string
age: number
readonly legs: number = 4
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
let c1 = new Cat2('小花',2)
c1.name ='小美'
// c1.legs=6 // 不能修改
console.log('姓名:',c1.name)
// 修饰符 private,protected
class Person {
private name: string = ''
protected age: number = 0
desc: string = '描述'
//类的内容,无论是私有还是保护,都是可以访问的
constructor(name:string,age:number) {
this.name = name
this.age = age
}
}
let p=new Person('小王',18)
console.log('实例访问:',p.name)// 无法再外部访问私有数据
console.log('实例访问:',p.age)// 无法再外部访问受保护数据
class Student extends Person {
sayHi() {
console.log('访问私有的数据:',super.name ) //私有数据无法再(子类)访问
console.log('访问受保护的数据:',super.age ) //受保护的数据可以在再(子类)访问
}
}
@Entry
@Component
struct classPage {
build(){}
}
剩余参数和展开运算符
剩余参数
展开运算符
接口补充
接口继承
接口实现
提高代码稳定性
泛型
泛型函数
// 泛型
function fn<FnType>(params:FnType[]):number{
return params.length
}
interface FnItem{
name:string
age:number
gender:boolean
}
const listParams:FnItem[]=[
{
name:'小花',
age:18,
gender:true
},
{
name:'小红',
age:19,
gender:true
},
{
name:'小军',
age:18,
gender:false
}
]
const fnResult = fn<FnItem>(listParams)
console.log('fnResult',fnResult)
@Entry
@Component
struct GenericsPage{
build() {
}
}
泛型约束
interface ILength {
length: number
}
function fn1<T extends ILength>(param: T) {
console.log('',param.length)
}
fn1<string>('abc')
fn1<number[]>([1,2,3])
class Desk {
length = 2
}
let d= new Desk()
fn1<Desk>(d)
@Entry
@Component
struct GenericsPage{
build() {
}
}
多个泛型参数
泛型接口
interface IdItem<T>{
id:(value:T)=>T
ids:()=>T[]
}
let obj:IdItem<number> ={
id:(value:number)=>{
return value
},
ids:()=>[1,2,3]
}
let obj2:IdItem<string> ={
id:(value:string)=>{
return value
},
ids:()=>['001','002','003']
}
@Entry
@Component
struct GenericsPage{
build() {
}
}
泛型类
class Person<T>{
name:string = '小十'
age:T
constructor(age:T) {
this.age = age
}
getAge(){
return this.age
}
}
let p1:Person<number>=new Person(18)
let p2:Person<string>=new Person('20')
模块化语法
模块化基本认知
模块化:把一个大的程序,【拆分】成若干的小的模块,通过【特定的语法】,可以进行任意组合
ArkTS 中每个 ets 文件,都可以看做是一个模块
默认导出和导入
默认导出:指一个模块,只能默认导出的 一个值或 对象。使用时,可以 自定义 导入名称。
使用步骤:
1.当前模块中 导出模块
2.需要使用的地方 导入模块
按需导出和导入
按需导出:指一个模块,可以按照需要,导出多个持性。
全部导入
将所有的按需导入,全部导入进来一 导出部分不需要调整,调整导入的语法即可
自定义组件
自定义组件的基本使用
概念:由框架直接提供的称为系统组件,由开发者定义的称为自定义组件
@Entry:文件入口加载
// 组件自定义
@Component
struct MyCom{
@State num:number=0
build() {
Row({space:20}){
Text(this.num.toString())
Button('+')
.onClick(()=>{
this.num++
})
}
}
}
// 头部组件
@Component
struct HeadCom{
build() {
Row(){
Text('这是头部').width('100%').height(100).backgroundColor(Color.Gray)
}
}
}
// 内容组件
@Component
struct ContentCom{
build() {
Column(){
MyCom()
MyCom()
MyCom()
}.width('100%').layoutWeight(1).backgroundColor('#ffc1c1c1')
}
}
// 尾部组件
@Component
struct FooterCom{
build() {
Row(){
Text('这是尾部').width('100%').height(100).backgroundColor(Color.Gray)
}
}
}
@Entry
@Component
struct Index {
build() {
Column(){
HeadCom()
ContentCom()
FooterCom()
}
}
}
自定义组件通用样式事件
自定义组件可以通过点语法,设置 通用样式,通用事件
自定义组件成员函数变量
除了必须要实现 build()函数外,还可以定义其他的成员函数,以及成员变量。
成员变量的值 →外部可传参覆盖
带有等号的变量 → 外部可传参覆盖
// 自定义组件
@Component
struct ItemPanel{
// 成员变量
title:string = '默认标题'
extra:string = '查看更多>'
content:string = '内容部分'
// 成员变量函数 - 可以外部传入覆盖
getMore = ()=>{
AlertDialog.show({
message:'获得更多'
})
}
// 成员函数 - 不可以外部传入覆盖
sayHi(){}
build() {
Column(){
Row(){
Text(this.title)
Text(this.extra)
.onClick(()=>{
this.getMore()
})
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Text(this.content)
}.width('100%').height(200)
.padding(10)
.backgroundColor(Color.White).borderRadius(20)
}
}
@Entry
@Component
struct MemberVariables{
build() {
Column({space:20}){
ItemPanel({
title:'我的订单',
extra:'全部订单 >',
getMore(){
AlertDialog.show({
message:'获取全部订单'
})
}
})
ItemPanel({
title:'小米有品众筹',
extra:'7款众筹中 >',
getMore(){
AlertDialog.show({
message:'获取众筹订单'
})
}
})
}.height('100%').width('100%')
.padding(20)
.backgroundColor(Color.Gray)
}
}
@BuilderParam
利用 @BuilderParam 构建函数,可以让自定义组件 允许外部传递 Ul,相当于插槽。
// 自定义组件
@Component
struct ItemPanel{
// 成员变量
title:string = '默认标题'
extra:string = '查看更多>'
content:string = '内容部分'
// 成员变量函数 - 可以外部传入覆盖
getMore = ()=>{
AlertDialog.show({
message:'获得更多'
})
}
// 成员函数 - 不可以外部传入覆盖
sayHi(){}
// 1.定义BuilderParam接受外部传入的ui,并设置默认值
@BuilderParam ContentBuilder:()=>void=this.defaultBuilder
// 2.设置默认的Builder
@Builder
defaultBuilder(){
Text('默认内容')
}
build() {
Column(){
Row(){
Text(this.title)
Text(this.extra)
.onClick(()=>{
this.getMore()
})
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Column(){
// Text(this.content)
// 3.使用@BuilderParam 装饰的成员变量
this.ContentBuilder()
}
}.width('100%').height(200)
.padding(10)
.backgroundColor(Color.White).borderRadius(20)
}
}
@Entry
@Component
struct MemberVariables{
build() {
Column({space:20}){
ItemPanel({
title:'我的订单',
extra:'全部订单 >',
getMore(){
AlertDialog.show({
message:'获取全部订单'
})
}
}){
Text('订单1')
Text('订单2')
Text('订单3')
Text('订单4')
}
ItemPanel({
title:'小米有品众筹',
extra:'7款众筹中 >',
getMore(){
AlertDialog.show({
message:'获取众筹订单'
})
}
}){
Button('众筹商品1')
Button('众筹商品2')
Button('众筹商品3')
}
}.height('100%').width('100%')
.padding(20)
.backgroundColor(Color.Gray)
}
}
多个BuilderParam
子组件有多个BuilderParam,必须通过参数的方式来传入
// 自定义组件
@Component
struct ItemPanel{
// 成员变量
title:string = '默认标题'
extra:string = '查看更多>'
content:string = '内容部分'
// 成员变量函数 - 可以外部传入覆盖
getMore = ()=>{
AlertDialog.show({
message:'获得更多'
})
}
// 成员函数 - 不可以外部传入覆盖
sayHi(){}
// 1.定义BuilderParam接受外部传入的ui,并设置默认值
@BuilderParam ContentLeftBuilder:()=>void=this.defaultBuilder
@BuilderParam ContentRightBuilder:()=>void=this.rightBuilder
// 2.设置默认的Builder
@Builder
defaultBuilder(){
Text('默认内容')
}
@Builder
rightBuilder(){
Button('右边')
}
build() {
Column(){
Row(){
Text(this.title)
Text(this.extra)
.onClick(()=>{
this.getMore()
})
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Row(){
// Text(this.content)
// 3.使用@BuilderParam 装饰的成员变量
Column(){
this.ContentLeftBuilder()
}
Column(){
this.ContentRightBuilder()
}
}
}.width('100%').height(200)
.padding(10)
.backgroundColor(Color.White).borderRadius(20)
}
}
@Entry
@Component
struct MemberVariables{
@Builder
leftBuilder(){
Text('小米众筹左边')
}
@Builder
rightBuilder(){
Button('小米众筹右边')
}
build() {
Column({space:20}){
ItemPanel({
title:'我的订单',
extra:'全部订单 >',
getMore(){
AlertDialog.show({
message:'获取全部订单'
})
}
})
ItemPanel({
title:'小米有品众筹',
extra:'7款众筹中 >',
getMore(){
AlertDialog.show({
message:'获取众筹订单'
})
},
ContentLeftBuilder:this.leftBuilder,
ContentRightBuilder:this.rightBuilder
})
}.height('100%').width('100%')
.padding(20)
.backgroundColor(Color.Gray)
}
}
装饰器
@state状态管理
当运行时的 状态变量 带来UI的重新渲染 在ArkUl中统称为 状态管理机制。变量必须被 装饰器@state 装饰才可以成为状态变量。
注意:不是状态变量的所有更改都会引起刷新。只有可以被框架观察到的修改才会引起Ul刷新。
1.boolean、string、number类型时,可以观察到数值的变化
2.class或者Object时,可观察 自身的赋值 的变化,第一层属性赋值的变化,即Object.keys(observedObject) 返回的属性。如果不是对象的第一层属性,修改时,需要修改整个嵌套的对象
Object.keys(observedObject):
@Prop-父子单向
@Prop 装饰的变量可以和父组件建立单向的同步关系。
@Prop 装饰的变量是可变的,但是变化不会同步回其父组件
// 子组件
@Component
struct SonCom{
@Prop SCar:string=''
text:string='子组件数据'
// 子向父传值
sonChangeCar=(val:string)=>{}
build() {
Column(){
Text(`子组件- ${this.SCar}`).fontColor(Color.White)
Button('子换车')
.onClick(()=>{
//1. prop--单项传递
// 子组件修改prop值,不会传递给父组件,会覆盖父组件的传值
// this.SCar = '小黄车'
// 2.子组件触发,父子同步修改
this.sonChangeCar(this.text)
})
}.width(180).height(100).backgroundColor(Color.Green).padding(10)
}
}
@Entry
@Component
struct CommunicateCom {
@State FCar:string ='劳斯莱斯'
build() {
Column({space:20}){
Text(`父组件 - ${this.FCar}`)
Button('父换车') .onClick(()=>{
this.FCar = '三轮车'
})
SonCom({
SCar:this.FCar,
// 这里必须用箭头函数,否则会有this指向问题
sonChangeCar:(val:string)=>{
// this.FCar = '超级钢铁侠'
this.FCar =val
}
})
}.width(200).height(300).backgroundColor(Color.Pink).padding(10)
}
}
@Link 双向同步
使用 @Link 可以实现父组件和子组件的 双向同步
使用步骤:
1.将父组件的状态属性传递给子组件
2.子组件通过@Link修饰即可
3.分别测试基础,和复杂类型
interface Person{
name:string
age:number
}
// 子组件
@Component
struct SonCom{
@Prop SCar:string=''
text:string='子组件数据'
// @Link定义的不设置默认初始值
@Link SCount:number
@Link person:Person
// 子向父传值
sonChangeCar=(val:string)=>{}
build() {
Column({space:20}){
Text(`子组件- ${this.SCar}`).fontColor(Color.White)
Button('子换车')
.onClick(()=>{
//1. prop--单项传递
// 子组件修改prop值,不会传递给父组件,会覆盖父组件的传值
// this.SCar = '小黄车'
// 2.子组件触发,父子同步修改
this.sonChangeCar(this.text)
})
// ----------------
Text(`子组件- ${this.SCount}`).fontColor(Color.White)
Button('SCount++')
.onClick(()=>{
this.SCount++
})
Text(JSON.stringify(this.person)).fontColor(Color.White)
Button('修改名字') .onClick(()=>{
this.person.name = '年轻小十'
})
}.width(300).height(500).backgroundColor(Color.Green).padding(10)
}
}
@Entry
@Component
struct CommunicateCom {
@State FCar:string ='劳斯莱斯'
@State count:number =10
@State person:Person={
name:'小十',
age:18
}
build() {
Column({space:20}){
Text(`父组件 - ${this.FCar}`)
Button('父换车') .onClick(()=>{
this.FCar = '三轮车'
})
// ------------------------
Text(`父组件 - ${this.count}`)
Button('count++') .onClick(()=>{
this.count++
})
Text(JSON.stringify(this.person))
Button('年纪++') .onClick(()=>{
this.person.age++
})
SonCom({
SCar:this.FCar,
// 这里必须用箭头函数,否则会有this指向问题
sonChangeCar:(val:string)=>{
// this.FCar = '超级钢铁侠'
this.FCar =val
},
SCount:this.count,
person:this.person
})
}.width('100%').height('100%').backgroundColor(Color.Pink).padding(10)
}
}
@Provide,@Consume后代组件
/*后代组件*/
/*子组件*/
@Component
struct Son1{
build() {
Column({space:20}){
Text('这是一级子组件')
Son2()
}.width('80%').height('40%').backgroundColor(Color.Pink).padding(20)
}
}
/*后代组件*/
@Component
struct Son2{
@Consume colorString:string
build() {
Column({space:20}){
Text('这是二级子组件').fontColor(Color.White)
Text(this.colorString).fontColor(Color.White).onClick(()=>{
this.colorString = 'pink'
})
}.width('80%').height('50%').backgroundColor(Color.Green).padding(20)
}
}
@Entry
@Component
struct DescendantComponents{
@Provide colorString:string = 'yellow'
build() {
Column({space:20}){
Text('这是父组件').fontColor(Color.White).fontSize(25)
Text(this.colorString).fontColor(Color.White)
Son1()
Son1()
}.width('100%').height('100%').backgroundColor(Color.Gray)
}
}
@Observed和@ObjectLink嵌套对象数组 属性变化
/*数据准备*/
interface IPerson{
id:number
name:string
age:number
}
// 定义类
@Observed
class Person{
id:number
name:string
age:number
constructor(obj:IPerson) {
this.id=obj.id
this.name=obj.name
this.age=obj.age
}
}
/*子组件*/
@Component
struct Son1{
@ObjectLink itemObj:Person
changAge =()=>{}
build() {
Row({space:20}){
Text('姓名:' + this.itemObj.name)
Text('年龄:' +this.itemObj.age)
Button('修改数据').onClick(()=>{
// 1.@ObjectLink绑定,深层次观察类 Person,监听并实现双向绑定
// this.itemObj.age++
// 2.通过父传递事件
this.changAge()
})
}.width('100%').height('20%').backgroundColor(Color.Pink).padding(20)
}
}
@Entry
@Component
struct DescendantComponents{
// 准备数据列表
@State dataList:IPerson[]=[
new Person({id:1,name:'小十',age:10}),
new Person({id:2,name:'金牛',age:18}),
new Person({id:3,name:'双子',age:13}),
]
build() {
Column({space:20}){
Text('这是父组件').fontColor(Color.White).fontSize(25)
ForEach(this.dataList,(item:Person,index:number)=>{
Son1({itemObj:item,changAge:()=>{
item.age++
}})
})
}.width('100%').height('100%').backgroundColor(Color.Gray)
}
}
掘金评论案例 -见仓库
路由
创建页面
页面体跳转和后退
// 两种导入都可以
import { router } from '@kit.ArkUI';
// import router from '@ohos.router';
interface IForm{
name:string
password:number|null
}
@Component
struct Son{
aboutToAppear(): void {
console.log('Son组件 -- aboutToAppear')
}
aboutToDisappear(): void {
console.log('Son组件 -- aboutToDisappear')
}
build() {
Column(){
Text('子组件Son')
}
}
}
@Entry
@Component
struct HomePage {
@State message: string = '首页';
@State formData:IForm ={name:'',password:null}
// 初始化数据
aboutToAppear(): void {
// 获取路由参数时router.getParams()不知道其中参数,这里需要类型断言as IForm
this.formData = router.getParams() as IForm
// AlertDialog.show({
// message:JSON.stringify(this.formData)
// })
console.log('Home页面 -- aboutToAppear')
}
build() {
Column({space:20}) {
Text(this.message)
.id('HomePageHelloWorld')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
Son()
Text('姓名' + this.formData.name)
Text('密码' + this.formData.password)
Button('返回登录')
.onClick(()=>{
// router.back()
router.pushUrl({
url:'pages/LoginPage'
})
})
Button('详情页')
.onClick(()=>{
router.pushUrl({
url:'pages/DetailPage'
})
})
Button('推荐页')
.onClick(()=>{
router.replaceUrl({
url:'pages/AboutPage'
})
})
}
.height('100%')
.width('100%')
}
}
页面栈
路由模式
生命周期
需要注意的是 页面和组件的生命周期不一样,会先加载完组件的生命周期在加载页面的周期
LoginPage
import { router } from '@kit.ArkUI';
// interface IForm{
// name:string
// password:number|null
// }
class IForm{
name?:string
password?:number
}
@Entry
@Component
struct LoginPage {
@State message: string = '登录';
@State name: string = '';
@State loginForm: IForm=new IForm()
aboutToAppear(): void {
console.log('Login页面 -- aboutToAppear')
}
aboutToDisappear(): void {
console.log('Login页面 -- aboutToDisappear')
}
onPageShow(): void {
console.log('Login页面 -- onPageShow')
}
onPageHide(): void {
console.log('Login页面 -- onPageHide')
}
onBackPress(): boolean | void {
console.log('Login页面 -- onBackPress')
return true
}
build() {
Column({space:20}) {
Text(this.message)
.id('LoginPageHelloWorld')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
TextInput({
placeholder:'输入用户名',
text:$$this.loginForm.name
})
TextInput({
placeholder:'输入密码',
text:$$this.loginForm.password
})
Button('主页')
.onClick(()=>{
router.replaceUrl({
url:'pages/HomePage',
params:this.loginForm
})
})
}
.height('100%')
.width('100%')
}
}
HomePage
// 两种导入都可以
import { router } from '@kit.ArkUI';
// import router from '@ohos.router';
// import { IForm } './LoginPage'
interface IForm{
name:string
password:number|null
}
@Component
struct Son{
aboutToAppear(): void {
console.log('Son组件 -- aboutToAppear')
}
aboutToDisappear(): void {
console.log('Son组件 -- aboutToDisappear')
}
build() {
Column(){
Text('子组件Son')
}
}
}
@Entry
@Component
struct HomePage {
@State message: string = '首页';
@State formData:IForm ={name:'',password:null}
// 初始化数据
aboutToAppear(): void {
// 获取路由参数时router.getParams()不知道其中参数,这里需要类型断言as IForm
this.formData = router.getParams() as IForm
// AlertDialog.show({
// message:JSON.stringify(this.formData)
// })
console.log('Home页面 -- aboutToAppear')
}
aboutToDisappear(): void {
console.log('Home页面 -- aboutToDisappear')
}
onPageShow(): void {
console.log('Home页面 -- onPageShow')
}
onPageHide(): void {
console.log('Home页面 -- onPageHide')
}
onBackPress(): boolean | void {
console.log('Home页面 -- onBackPress')
router.back()
return true
}
build() {
Column({space:20}) {
Text(this.message)
.id('HomePageHelloWorld')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
Son()
Text('姓名' + this.formData.name)
Text('密码' + this.formData.password)
Button('返回登录')
.onClick(()=>{
// router.back()
router.pushUrl({
url:'pages/LoginPage'
})
})
Button('详情页')
.onClick(()=>{
router.pushUrl({
url:'pages/DetailPage'
})
})
Button('推荐页')
.onClick(()=>{
router.replaceUrl({
url:'pages/AboutPage'
})
})
}
.height('100%')
.width('100%')
}
}
解析
Stage模型
目录概览
app.json5应用配置
配置的是设置应用里面的 注意修改版本时需要将原来app卸载重启
module.json5配置文件
配置的是桌面的图标和名字
改桌面名字时,需要如下操作,改中英文
UiAbility组件
模块新增:
一个应用可以有多个模块
模块UiAbility组件加载页面配置
在模块中新建新的ability
同一个模块何以通过不同的入口进入不同的页面
ability生命周期
同模块拉起另一个UIAbility
每个ability都有独立的生命周期,同一个模块不同的ability之间可以页面互相跳转
// 两种导入都可以
import { router } from '@kit.ArkUI';
// import router from '@ohos.router';
// import { IForm } './LoginPage'
import Want from '@ohos.app.ability.Want'
import {common} from '@kit.AbilityKit'
import {BusinessError} from '@kit.BasicServicesKit'
interface IForm{
name:string
password:number|null
}
@Component
struct Son{
aboutToAppear(): void {
console.log('Son组件 -- aboutToAppear')
}
aboutToDisappear(): void {
console.log('Son组件 -- aboutToDisappear')
}
build() {
Column(){
Text('子组件Son')
}
}
}
@Entry
@Component
struct HomePage {
// ------------------------------同模块启动另一个ability---------
context = getContext(this) as common.UIAbilityContext
@State message: string = '首页';
@State formData:IForm ={name:'',password:null}
// 初始化数据
aboutToAppear(): void {
// 获取路由参数时router.getParams()不知道其中参数,这里需要类型断言as IForm
this.formData = router.getParams() as IForm
// AlertDialog.show({
// message:JSON.stringify(this.formData)
// })
console.log('Home页面 -- aboutToAppear')
}
aboutToDisappear(): void {
console.log('Home页面 -- aboutToDisappear')
}
onPageShow(): void {
console.log('Home页面 -- onPageShow')
}
onPageHide(): void {
console.log('Home页面 -- onPageHide')
}
onBackPress(): boolean | void {
console.log('Home页面 -- onBackPress')
router.back()
return true
}
build() {
Column({space:20}) {
Text(this.message)
.id('HomePageHelloWorld')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
Son()
Text('姓名' + this.formData.name)
Text('密码' + this.formData.password)
Button('返回登录')
.onClick(()=>{
// router.back()
router.pushUrl({
url:'pages/LoginPage'
})
})
Button('详情页')
.onClick(()=>{
router.pushUrl({
url:'pages/DetailPage'
})
})
Button('推荐页')
.onClick(()=>{
router.replaceUrl({
url:'pages/AboutPage'
})
})
// ------------------------------同模块启动另一个ability---------
Button('买菜功能--唤起同模块的abillty')
.onClick(()=>{
let wantInfo :Want={
deviceId:'', // 空表示本设备
bundleName:'com.example.threepart', // appScope>app.json5里面
moduleName:'entry', // 需要唤起的模块名
abilityName:'TwoAbility1', // src/main/module.json5里面除开本ability外另外一个ability名字
parameters:{
info:'来自entryability'
}
}
this.context.startAbility(wantInfo)
.then(()=>{
console.log('startAbility成功')
})
.catch((error:BusinessError)=>{
console.log('startAbility失败')
})
})
Button('买菜功能--唤起不同模块的abillty')
.onClick(()=>{
let wantInfo :Want={
deviceId:'', // 空表示本设备
bundleName:'com.example.threepart', // appScope>app.json5里面
moduleName:'TestModel', // 需要唤起的模块名
abilityName:'TestModelAbility', // src/main/module.json5里面除开本ability外另外一个ability名字
parameters:{
info:'来自entryability'
}
}
this.context.startAbility(wantInfo)
.then(()=>{
console.log('startAbility成功')
})
.catch((error:BusinessError)=>{
console.log('startAbility失败')
})
})
}
.height('100%')
.width('100%')
}
}