装饰器
@State
在声明式UI中,是以状态驱动试图更新:
状态(State):指驱动视图更新的数据(被装饰器标记的变量)
视图(View):基于UI描述渲染得到用户界面
说明:
@State装饰器标记的变量必须初始化,,不能为空值
@State支持Object,class,string,number,boolean,enum类型以及这些类型的数组
嵌套类型以及数组中的对象属性无法触发试图更新
@Prop 和 @Link
当父子组件之间需要数据同步时,可以使用@Prop 跟C++函数传值差不多和@Link装饰器跟C++函数传引用差不多。
// @ts-nocheck
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 StatInfo {
// 总任务量
totalTask: number = 0
// 已完成任务数量
finishTask: number = 0
}
@Entry
@Component
struct PropPage{
// 总任务量
@State stat: StatInfo = new StatInfo()
build(){
Column({space: 10}){
// 1. 任务进度卡片
TaskStatistics({finishTask: this.stat.finishTask, totalTask: this.stat.totalTask})
// 2. 新增任务按钮
TaskList({stat: $stat})
}
.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()
.margin({top: 20, bottom: 10})
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
@Link stat: StatInfo
// 任务数组
@State tasks: Task[] = []
handleTaskChange(){
// 2. 更新任务总数量
this.stat.finishTask = this.tasks.filter(item => item.finished).length
// 2. 更新任务总数量
this.stat.totalTask = this.tasks.length
}
build()
{
Column() {
Button('新增任务')
.width(200)
.onClick(() => {
// 1. 新增任务数量
this.tasks.push(new Task())
this.handleTaskChange()
})
// 3. 任务列表
List({ space: 10 }) {
ForEach(
this.tasks,
(item, index) => {
ListItem() {
Row() {
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val => {
// 1. 更新当前任务状态
item.finished = val
// 2. 更新任务总数量
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({ end: this.DeleteButton(index) })
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.delete'))
.width(30)
}
.width(40)
.height(40)
.backgroundColor(Color.Red)
.type(ButtonType.Circle)
.margin(5)
.onClick(() => {
this.tasks.splice(index, 1)
this.handleTaskChange()
})
}
}
@Provide 和 @Consume 可以夸组件提供类似于@State和@Link的双向同步
@ObjectLink 和 @Observed
@ObjectLink 和 @Observed装饰器用于在涉及嵌套对象或数组元素为对象的场景中进行双向数据同步。
// @ts-nocheck
@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 StatInfo {
// 总任务量
totalTask: number = 0
// 已完成任务数量
finishTask: number = 0
}
@Entry
@Component
struct PropPage{
// 总任务量
@State stat: StatInfo = new StatInfo()
build(){
Column({space: 10}){
// 1. 任务进度卡片
TaskStatistics({finishTask: this.stat.finishTask, totalTask: this.stat.totalTask})
// 2. 新增任务按钮
TaskList({stat: $stat})
}
.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()
.margin({top: 20, bottom: 10})
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
@Link stat: StatInfo
// 任务数组
@State tasks: Task[] = []
handleTaskChange(){
// 2. 更新任务总数量
this.stat.finishTask = this.tasks.filter(item => item.finished).length
// 2. 更新任务总数量
this.stat.totalTask = this.tasks.length
}
build()
{
Column() {
Button('新增任务')
.width(200)
.onClick(() => {
// 1. 新增任务数量
this.tasks.push(new Task())
this.handleTaskChange()
})
// 3. 任务列表
List({ space: 10 }) {
ForEach(
this.tasks,
(item:Task, index) => {
ListItem() {
TeskItem({ item: item, OnTaskChange: this.handleTaskChange.bind(this)})
}
.swipeAction({ end: this.DeleteButton(index) })
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.delete'))
.width(30)
}
.width(40)
.height(40)
.backgroundColor(Color.Red)
.type(ButtonType.Circle)
.margin(5)
.onClick(() => {
this.tasks.splice(index, 1)
this.handleTaskChange()
})
}
}
@Component
struct TeskItem {
@ObjectLink item: Task
OnTaskChange: () => 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 => {
// 1. 更新当前任务状态
this.item.finished = val
// 2. 更新任务总数量
this.OnTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
}