arkTS笔记
官方API:快速入门-入门 | 华为开发者联盟 (huawei.com)
仓库地址:https://gitee.com/huyi612/harmonyos-lessons
一、初识arkTS
1.项目结构
2.从helloworld案例认识代码结构
二、arkUI
1.基础组件
(1)Image组件
ts
Image($r('app.media.icon'))
.width(this.imageWidth)
.interpolation(ImageInterpolation.High)
(2)Text组件
ts
Text($r('app.string.width_label'))
.fontSize(20)
.fontWeight(FontWeight.Bold)
(3)TextInput组件
ts
TextInput({ placeholder: '请输入图片宽度', text: this.imageWidth.toFixed(0) })
.width(150)
.backgroundColor('#fff')
.type(InputType.Number)
.onChange(value => {
if (value) {
this.imageWidth = parseInt(value)
}
})
(4)Button组件
ts
Button('放大')
.width(80)
.fontSize(20)
.onClick(() => {
if (this.imageWidth < 300) {
this.imageWidth += 10
}
}
(5)Slider组件
ts
Slider({
min: 0,
max: 300,
value: this.imageWidth,
step: 10
})
.width('90%')
.blockColor('#36D')
.trackThickness(6)
.showTips(true)
.onChange(value => {
this.imageWidth = value
}
(6)横线Divider
ts
Divider().color($r('app.color.primary_color'))
(7)滑动删除按钮(swipeAction)
ts
@Builder deleteButton(){
Image($r('app.media.ic_public_delete_filled'))
.width(20)
.fillColor(Color.Red)
.margin(5)
}
ListItem() {
Row({ space: CommonConstants.SPACE_6 }) {
Image($r('app.media.toast')).width(50)
Column({ space: CommonConstants.SPACE_4 }) {
Text('全麦吐司').fontWeight(CommonConstants.FONT_WEIGHT_500)
Text('1片').grayText()
}
Blank()
Text('91千卡').grayText()
}
.width('100%')
.padding(CommonConstants.SPACE_6)
}
.swipeAction({end : this.deleteButton.bind(this)})
(8)Tabs组件
ts
(9)组件面板(Panle)
ts
2.UI组件(容器组件)
(1)Column组件与Row组件
(2)FlexAlign
justifyContent:
alignItems:
(3)Grid网格容器
ts
(4)盒子模型
3.列表渲染:forEach
ts
// 继承模式,只能写在全局
@Extend(Text) function textPrice(){
.width('100%')
.fontColor('#f36')
.fontSize(18)
}
import { Header } from '../common/components/commonComponents'
@Entry
@Component
struct ItemList {
// 商品数据
private items: Array<Item> = [
new Item('华为Mate60', $r('app.media.mate60'), 6999, 5999),
new Item('MateBookProX', $r('app.media.mateBookProX'), 13999),
new Item('WatchGT4', $r('app.media.freeBudsPro3'), 1438),
new Item('华为Mate60', $r('app.media.mate60'), 6999, 5999),
new Item('MateBookProX', $r('app.media.mateBookProX'), 13999),
new Item('WatchGT4', $r('app.media.freeBudsPro3'), 1438),
new Item('华为Mate60', $r('app.media.mate60'), 6999, 5999),
new Item('MateBookProX', $r('app.media.mateBookProX'), 13999),
new Item('WatchGT4', $r('app.media.freeBudsPro3'), 1438)
]
// 局部自定义构建函数
@Builder ItemCard(item:Item) {
Row({ space: 10 }) {
Image(item.image)
.width(100)
Column({ space: 4 }) {
if (item.discount) {
Text(item.name)
.width('100%')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('原价:¥' + item.price)
.width('100%')
.fontColor('#ccc')
.fontSize(14)
.decoration({ type: TextDecorationType.LineThrough })
Text('折扣价:¥' + item.discount)
.textPrice()
Text('补贴价:¥' + (item.price - item.discount))
.textPrice()
} else {
Text(item.name)
.width('100%')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('¥' + item.price)
.textPrice()
}
}
.height('100%')
}
.width('100%')
.backgroundColor('#fff')
.borderRadius(20)
.height(120)
.padding(10)
}
// 局部公开样式函数
@Styles fillScreen() {
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
.padding(20)
}
build() {
Column({ space: 8 }) {
Header({ title: '商品列表' })
.margin({ bottom: 20 })
List({ space: 8 }) {
ForEach(this.items, (item: Item) => {
ListItem() {
this.ItemCard(item)
}
})
}
.width('100%')
.layoutWeight(1)
}
.fillScreen()
}
}
4.List列表
ts
List({ space: 8 }) {
ForEach(this.items, (item: Item) => {
ListItem() {
this.ItemCard(item)
}
})
}
5.@Component和@Builder
ts
import router from '@ohos.router'
@Component
export struct Header {
// 标题
private title: ResourceStr
// id
@State params: any = router.getParams()
build() {
Row() {
Image($r('app.media.return'))
.width(30)
.onClick(() => {
// 返回前的警告
// router.showAlertBeforeBackPage({message:'当前还未支付,确定要返回吗?'})
// 返回路由
router.back()
})
if (this.params.id && this.title) {
Text(this.params.id + '.' + this.title)
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
Blank()
Image($r('app.media.refresh'))
.width(30)
}
.width('100%')
.height(30)
}
}
ts
// 局部自定义构建函数
@Builder ItemCard(item: Item) {
Row({ space: 10 }) {
Image(item.image)
.width(100)
Column({ space: 4 }) {
if (item.discount) {
Text(item.name)
.width('100%')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('原价:¥' + item.price)
.width('100%')
.fontColor('#ccc')
.fontSize(14)
.decoration({ type: TextDecorationType.LineThrough })
Text('折扣价:¥' + item.discount)
.textPrice()
Text('补贴价:¥' + (item.price - item.discount))
.textPrice()
} else {
Text(item.name)
.width('100%')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('¥' + item.price)
.textPrice()
}
}
.height('100%')
}
.width('100%')
.backgroundColor('#fff')
.borderRadius(20)
.height(120)
.padding(10)
}
6.@Styles和@Extend
ts
// 局部公开样式函数
@Styles fillScreen() {
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
.padding(20)
}
ts
// 继承模式,只能写在全局
@Extend(Text) function textPrice() {
.width('100%')
.fontColor('#f36')
.fontSize(18)
}
三、状态管理
官网图片:
状态管理概述-状态管理-学习ArkTS语言-入门 | 华为开发者联盟 (huawei.com)
1.@State
2.@Prop & @Link
ts
// Prop
@State amount:number = 1 // 父组件
ItemPanelCard({amount: this.amount}) // 父组件传值
@Prop amount: number // 子组件接收
3.@Provide&@Consume
4.@Observed&@ObjectLink
ts
// 任务类
import { Header } from '../common/components/commonComponents'
@Observed
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')
}
class statTask {
// 总任务数量
totalTask: number = 0
// 已完成任务数量
finishTask: number = 0
}
@Entry
@Component
struct PropPage {
@State stat:statTask = new statTask()
build() {
Column({ space: 10 }) {
Header()
// 1.任务进度卡片
TaskStatistics({ finishTask: this.stat.finishTask, totalTask: this.stat.totalTask }) // 传@Prop用this.
// 2.新增任务按钮
// 3.任务列表
TaskList({ stat:$stat }) // 传@Link用$
.layoutWeight(1)
}
.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())
.fontSize(24)
.fontColor('#36D')
Text('/' + this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.justifyContent(FlexAlign.SpaceEvenly)
.margin({ top: 20 })
}
}
@Component
struct TaskList {
// 总任务数量
@Link stat:statTask
// 任务数组
@State tasks: Task[] = []
build() {
Column({space:10}) {
Button('新增任务')
.width(200)
.onClick(() => {
// 1.新增任务数据
this.tasks.push(new Task())
// 2. 更新任务总数量
this.stat.totalTask = this.tasks.length
})
List({ space: 10 }) {
ForEach(this.tasks, (item: Task, index) => {
ListItem() {
TaskItem({item:item,onChangeItem:this.TaskChangeHandler.bind(this)})
}
.swipeAction({ end: this.DeleteButton(index) })
})
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
TaskChangeHandler(){
// 更新已完成任务数量
this.stat.finishTask = this.tasks.filter(item => item.finished).length
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.delete'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.tasks.splice(index, 1)
this.stat.totalTask = this.tasks.length
this.stat.finishTask = this.tasks.filter(item => item.finished).length
})
}
}
@Component
struct TaskItem{
@ObjectLink item:Task
onChangeItem:()=>void
build(){
Row() {
if(this.item.finished){
Text(this.item.name)
.fontSize(20)
.finishedTask()
}else{
Text(this.item.name)
.fontSize(20)
}
Checkbox()
.select(this.item.finished)
.onChange(val => {
// 更新当前任务状态
this.item.finished = val
// 更新已完成任务数量
this.onChangeItem()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
}
5.@StorageProp(应用级)
ts
// 保存日期到全局存储 getTime() => number 适用于全局监控
AppStorage.SetOrCreate('selectedDate',this.selectedDate.getTime())
ts
// 全局时间选择管理
@StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
6.函数传递(子组件更改父组件)
ts
// 父组件定义函数 父组件传递函数 子组件触发函数
build() {
Column() {
// 1. 头部导航
this.Header()
// 2. 列表
ItemList({showPanel: this.onShowPanel.bind(this)}) // 子组件函数:showPanel 父组件函数:onShowPanel
// 3. 面板
Panel(this.isShow)
}
.width('100%')
.height('100%')
}
四、页面路由(Router)
1.路由跳转api
五、动画
1.属性动画(animation)
2.显式动画(AnimateTo)
3.组件转场动画(transition)
六、Stage模型
1.概述
2.应用配置文件
3、UIAbility生命周期
4、页面及组件生命周期
5、UIAbility的启动模式
MyAbility.ts文件配置:
ts
import AbilityStage from '@ohos.app.ability.AbilityStage';
import Want from '@ohos.app.ability.Want';
export default class MyAbilityStage extends AbilityStage {
onAcceptWant(want:Want):string {
if(want.abilityName == 'DocumentAbility') {
return `DocAbilityInstance_${want.parameters.instanceKey}`
}
return ''
}
}
七、HTTP网络请求
ts
import http from '@ohos.net.http';
import ShopInfo from '../viewmodel/ShopInfo';
import axios from '@ohos/axios'
class ShopModel {
baseURL: string = 'http://localhost:3000'
pageNo: number = 1
/**
* 基于axios实现异步查询商铺
* @returns
*/
getShopListByAxios(): Promise<ShopInfo[]> {
return new Promise((resolve, reject) => {
axios.get(
`${this.baseURL}/shops`,
{
params: { pageNo: this.pageNo, pageSize: 3 }
}
)
.then(resp => {
if (resp.status === 200) {
// 查询成功
console.log('testTag', '查询商铺成功!', JSON.stringify(resp.data))
resolve(resp.data)
} else {
console.log('testTag', '查询商铺信息失败!error:', JSON.stringify(resp))
reject('查询商铺失败')
}
})
.catch(error => {
console.log('testTag', '查询商铺信息失败!error:', JSON.stringify(error))
reject('查询商铺失败')
})
})
}
/**
* 基于ohos的http模块实现异步查询商铺
* @returns
*/
getShopListByHttp(): Promise<ShopInfo[]> {
return new Promise((resolve, reject) => {
// 1.创建http的请求对象
let httpRequest = http.createHttp()
// 2.发送请求
httpRequest.request(
`${this.baseURL}/shops?pageNo=${this.pageNo}&pageSize=3`,
{
method: http.RequestMethod.GET
}
)
.then(resp => {
if (resp.responseCode === 200) {
// 查询成功
console.log('testTag', '查询商铺成功!', resp.result)
resolve(JSON.parse(resp.result.toString()))
} else {
console.log('testTag', '查询商铺信息失败!error:', JSON.stringify(resp))
reject('查询商铺失败')
}
})
.catch(error => {
console.log('testTag', '查询商铺信息失败!error:', JSON.stringify(error))
reject('查询商铺失败')
})
})
}
/**
* 基于axios实现同步查询商铺
* @returns
*/
async getShopListByAxiosAsync(): Promise<ShopInfo[]> {
// 1.发送请求
let resp = await axios.get(
`${this.baseURL}/shops`,
{
params: { pageNo: this.pageNo, pageSize: 3 }
}
)
// 2.处理响应
if (resp.status === 200) {
// 查询成功
console.log('testTag', '查询商铺成功!', JSON.stringify(resp.data))
return resp.data;
}
// 查询失败
console.log('testTag', '查询商铺信息失败!error:', JSON.stringify(resp))
}
/**
* 基于ohos的http模块实现同步查询商铺
* @returns
*/
async getShopListByHttpAsync(): Promise<ShopInfo[]> {
// 1.创建http的请求对象
let httpRequest = http.createHttp()
// 2.发送请求
let resp = await httpRequest.request(
`${this.baseURL}/shops?pageNo=${this.pageNo}&pageSize=3`,
{
method: http.RequestMethod.GET
}
)
// 3.处理响应
if (resp.responseCode === 200) {
// 查询成功
console.log('testTag', '查询商铺成功!', resp.result)
return JSON.parse(resp.result.toString());
}
console.log('testTag', '查询商铺信息失败!error:', JSON.stringify(resp))
}
}
const shopModel = new ShopModel();
export default shopModel as ShopModel;
八、数据持久化
1.用户首选项(Preference)
2.关系型数据库(relationStore)
步骤:
ts
import relationalStore from '@ohos.data.relationalStore';
import TaskInfo from '../../../../../../../前端学习笔记+资料/arkTS笔记/MyApplication/entry/src/main/ets/viewmodel/TaskInfo';
class TaskModel {
private rdbStore: relationalStore.RdbStore
private tableName: string = 'TASK'
/**
* 初始化任务表
*/
initTaskDB(context){
// 1.rdb配置
const config = {
name: 'MyApplication.db',
securityLevel: relationalStore.SecurityLevel.S1
}
// 2.初始化SQL语句
const sql = `CREATE TABLE IF NOT EXISTS TASK (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
NAME TEXT NOT NULL,
FINISHED bit
)`
// 3.获取rdb
relationalStore.getRdbStore(context, config, (err, rdbStore) => {
if(err){
console.log('testTag', '获取rdbStore失败!')
return
}
// 执行Sql
rdbStore.executeSql(sql)
console.log('testTag', '创建task表成功!')
// 保存rdbStore
this.rdbStore = rdbStore
})
}
/**
* 查询任务列表
*/
async getTaskList(){
// 1.构建查询条件
let predicates = new relationalStore.RdbPredicates(this.tableName)
// 2.查询
let result = await this.rdbStore.query(predicates, ['ID', 'NAME', 'FINISHED'])
// 3.解析查询结果
// 3.1.定义一个数组,组装最终的查询结果
let tasks: TaskInfo[] = []
// 3.2.遍历封装
while(!result.isAtLastRow){
// 3.3.指针移动到下一行
result.goToNextRow()
// 3.4.获取数据
let id = result.getLong(result.getColumnIndex('ID'))
let name = result.getString(result.getColumnIndex('NAME'))
let finished = result.getLong(result.getColumnIndex('FINISHED'))
// 3.5.封装到数组
tasks.push({id, name, finished: !!finished})
}
console.log('testTag', '查询到数据:', JSON.stringify(tasks))
return tasks
}
/**
* 添加一个新的任务
* @param name 任务名称
* @returns 任务id
*/
addTask(name: string): Promise<number>{
return this.rdbStore.insert(this.tableName, {name, finished: false})
}
/**
* 根据id更新任务状态
* @param id 任务id
* @param finished 任务是否完成
*/
updateTaskStatus(id: number, finished: boolean) {
// 1.要更新的数据
let data = {finished}
// 2.更新的条件
let predicates = new relationalStore.RdbPredicates(this.tableName)
predicates.equalTo('ID', id)
// 3.更新操作
return this.rdbStore.update(data, predicates)
}
/**
* 根据id删除任务
* @param id 任务id
*/
deleteTaskById(id: number){
// 1.删除的条件
let predicates = new relationalStore.RdbPredicates(this.tableName)
predicates.equalTo('ID', id)
// 2.删除操作
return this.rdbStore.delete(predicates)
}
}
let taskModel = new TaskModel();
export default taskModel as TaskModel;
九、通知
1.基础通知(notificationManager)
2.进度条通知(notification)
3.通知意图(Want)
ts
import notify from '@ohos.notificationManager'
import image from '@ohos.multimedia.image'
import DownloadCard from '../views/notification/DownloadCard'
import { Header } from '../common/components/CommonComponents'
@Entry
@Component
struct NotificationPage {
// 全局任务id
idx: number = 100
// 图象
pixel: PixelMap
async aboutToAppear() {
// 获取资源管理器
let rm = getContext(this).resourceManager;
// 读取图片
let file = await rm.getMediaContent($r('app.media.watchGT4'))
// 创建PixelMap
image.createImageSource(file.buffer).createPixelMap()
.then(value => this.pixel = value)
.catch(reason => console.log('testTag', '加载图片异常', JSON.stringify(reason)))
}
build() {
Column({space: 20}) {
Header({title: '通知功能'})
Button(`发送normalText通知`)
.onClick(() => this.publishNormalTextNotification())
Button(`发送longText通知`)
.onClick(() => this.publishLongTextNotification())
Button(`发送multiLine通知`)
.onClick(() => this.publishMultiLineNotification())
Button(`发送Picture通知`)
.onClick(() => this.publishPictureNotification())
// 下载功能卡片
DownloadCard()
}
.width('100%')
.height('100%')
.padding(5)
.backgroundColor('#f1f2f3')
}
publishNormalTextNotification() {
let request: notify.NotificationRequest = {
id: this.idx++,
content: {
contentType: notify.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: '通知标题' + this.idx,
text: '通知内容详情',
additionalText: '通知附加内容'
}
},
showDeliveryTime: true,
deliveryTime: new Date().getTime(),
groupName: 'wechat',
slotType: notify.SlotType.SOCIAL_COMMUNICATION
}
this.publish(request)
}
publishLongTextNotification() {
let request: notify.NotificationRequest = {
id: this.idx++,
content: {
contentType: notify.ContentType.NOTIFICATION_CONTENT_LONG_TEXT,
longText: {
title: '通知标题' + this.idx,
text: '通知内容详情',
additionalText: '通知附加内容',
longText: '通知中的长文本,我很长,我很长,我很长,我很长,我很长,我很长,我很长',
briefText: '通知概要和总结',
expandedTitle: '通知展开时的标题' + this.idx
}
}
}
this.publish(request)
}
publishMultiLineNotification() {
let request: notify.NotificationRequest = {
id: this.idx++,
content: {
contentType: notify.ContentType.NOTIFICATION_CONTENT_MULTILINE,
multiLine: {
title: '通知标题' + this.idx,
text: '通知内容详情',
additionalText: '通知附加内容',
briefText: '通知概要和总结',
longTitle: '展开时的标题,我很宽,我很宽,我很宽',
lines: [
'第一行',
'第二行',
'第三行',
'第四行',
]
}
}
}
this.publish(request)
}
publishPictureNotification() {
let request: notify.NotificationRequest = {
id: this.idx++,
content: {
contentType: notify.ContentType.NOTIFICATION_CONTENT_PICTURE,
picture: {
title: '通知标题' + this.idx,
text: '通知内容详情',
additionalText: '通知附加内容',
briefText: '通知概要和总结',
expandedTitle: '展开后标题' + this.idx,
picture: this.pixel
}
}
}
this.publish(request)
}
private publish(request: notify.NotificationRequest) {
notify.publish(request)
.then(() => console.log('notify test', '发送通知成功'))
.then(reason => console.log('notify test', '发送通知失败', JSON.stringify(reason)))
}
}
十、自定义弹窗@CustomDialog
ts
import { CommonConstants } from '../../common/constants/CommonConstants'
@Preview
@CustomDialog
export default struct UserPrivacyDialog {
controller: CustomDialogController
confirm: ()=> void
cancel: ()=> void
build() {
Column({space:10}){
// 1.标题
Text('欢迎使用健康监控')
.fontSize(20)
.fontWeight(CommonConstants.FONT_WEIGHT_700)
// 2.内容
Text($r('app.string.user_privacy_content'))
// 3.按钮
Button($r('app.string.agree_label'))
.width(150)
.backgroundColor($r('app.color.primary_color'))
.onClick(()=>{
this.confirm()
this.controller.close()
})
Button($r('app.string.refuse_label'))
.width(150)
.backgroundColor($r('app.color.lightest_primary_color'))
.fontColor($r('app.color.light_gray'))
.onClick(()=>{
this.cancel()
this.controller.close()
})
}
.width('100%')
.padding(10)
}
}
十一、多设备响应式布局
媒体查询
ts
// 1.导入媒体查询模块
import mediaQuery from '@ohos.mediaquery'
import BreakpointConstants from '../constants/BreakpointConstants'
export default class BreakPointSystem{
// 2.设置媒体查询条件,并获取对应的listener
private smListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_SM)
private mdListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_MD)
private lgListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_LG)
smListenerCallBack(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakPoint(BreakpointConstants.BREAKPOINT_SM)
}
}
mdListenerCallBack(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakPoint(BreakpointConstants.BREAKPOINT_MD)
}
}
lgListenerCallBack(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakPoint(BreakpointConstants.BREAKPOINT_LG)
}
}
// 4.将设备状态记录到全局状态中
updateCurrentBreakPoint(breakPoint: string){
AppStorage.SetOrCreate(BreakpointConstants.CURRENT_BREAKPOINT,breakPoint)
}
// 3.给listener设置回调函数,当设备状态变化时会执行回调函数
register(){
this.smListener.on('change',this.smListenerCallBack.bind(this))
this.mdListener.on('change',this.mdListenerCallBack.bind(this))
this.lgListener.on('change',this.lgListenerCallBack.bind(this))
}
unregister(){
this.smListener.off('change',this.smListenerCallBack.bind(this))
this.mdListener.off('change',this.mdListenerCallBack.bind(this))
this.lgListener.off('change',this.lgListenerCallBack.bind(this))
}
}