组件样式复用
@Styles和@Extend
将多条样式设置提炼成一个方法,然后在各个组件声明的位置进行调用,完成样式的复用
@style
可定义在组件内或全局,只能包含通用属性,不能传参
@Entry
@Component
struct Index{
@State num:number = 1
build() {
Column(){
Row({space:50}){
Button('确认')
.type(ButtonType.Normal)
.backgroundColor(Color.Green)
.comButtonStyle()//复用样式
.onClick(()=>console.log('点击确认键'))
Button('取消')
.type(ButtonType.Normal)
.backgroundColor(Color.Gray)
.comButtonStyle()
.onClick(()=>console.log('点击取消键'))
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
//组件内定义
@Styles comButtonStyle(){
.width(100)
.height(40)
.borderRadius(10)
}
}
// 全局定义样式,在当前页面中全局可用
@Styles
function globalButtonStyle( ) {
.width(100)
.height(40)
.borderRadius(10)
}
@Extend
同样可以用于组件样式的复用,与@Styles不同的是,@Extend只能定义在全局,且只能用于指定类型的组件
如下可以理解为Button组件的样式拓展,方法中可能包含指定组件的专有属性和专有方法
@Entry
@Component
struct Index{
@State num:number = 1
build() {
Column(){
Row({space:50}){
Button('确认')
.type(ButtonType.Normal)
.backgroundColor(Color.Green)
.comButtonStyle()//复用样式
.onClick(()=>console.log('点击确认键'))
Button('取消')
.buttonExtendStyle(Color.Gray,()=>{
console.log('点击取消键');
})
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
//组件内定义
// 不能有参数
@Styles comButtonStyle(){
// .backgroundColor(color)
.width(100)
.height(40)
.borderRadius(10)
}
}
// 全局定义样式
@Styles
function globalButtonStyle( ) {
.width(100)
.height(40)
.borderRadius(10)
}
@Extend(Button)
function buttonExtendStyle(color:Color,callback:()=>void ) {
.width(100)
.height(40)
.borderRadius(10)
.type(ButtonType.Capsule)
.backgroundColor(color)
.onClick(callback)
}
UI结构复用
@Builder方法
除自定义组件外,arkTS提供了更加轻量的UI结构的复用机制,@Builder方法
可声明在组件内或全局
1、组件内的@Builder方法,通过this调用,只能用于当前组件,
2、全局的@Builder方法,不用通过this调用,导出(export)之后,可用于整个应用,
@Entry
@Component
struct Index{
@State num:number = 1
build() {
Column(){
Row({space:50}){
Button('确认')
.type(ButtonType.Normal)
.backgroundColor(Color.Green)
.comButtonStyle()//复用样式
.onClick(()=>console.log('点击确认键'))
Button('取消')
.buttonExtendStyle(Color.Gray,()=>{
console.log('点击取消键');
})
}
Button(){
Row(){
Image($r('app.media.app_icon'))
.width(25)
.height(25)
Text('发送')
.fontSize(25)
.fontColor(Color.White)
}
}
.width(120)
.height(50)
.onClick(()=>{console.log('发送')})
this.compButtonBuilder($r('app.media.app_icon'),'send',()=>console.log('send'))
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
//组件内定义
// 不能有参数
@Styles comButtonStyle(){
// .backgroundColor(color)
.width(100)
.height(40)
.borderRadius(10)
}
@Builder compButtonBuilder(icon:Resource,text:string,callback:()=>void){
Button(){
Row(){
Image($r('app.media.app_icon'))
.width(25)
.height(25)
Text(text)
.fontSize(25)
.fontColor(Color.White)
}
.width(120)
.height(50)
.onClick(callback)
}
}
}
// 全局定义样式
@Styles
function globalButtonStyle( ) {
.width(100)
.height(40)
.borderRadius(10)
}
@Extend(Button)
function buttonExtendStyle(color:Color,callback:()=>void ) {
.width(100)
.height(40)
.borderRadius(10)
.type(ButtonType.Capsule)
.backgroundColor(color)
.onClick(callback)
}
@Builder
export function compButtonBuilder(icon:Resource,text:string,callback:()=>void ) {
Button(){
Row(){
Image($r('app.media.app_icon'))
.width(25)
.height(25)
Text(text)
.fontSize(25)
.fontColor(Color.White)
}
.width(120)
.height(50)
.onClick(callback)
}
}
@Builder方法参数传递规则
当以对象字面量的方式传值,若传递的参数为状态变量,则状态变量的变化会引起@Builder方法内部UI刷新,按值传递则不会
@Builder与自定义组件的区别
1、都可以实现UI复用的效果,
2、自定义组件可以定义自己的状态变量,而@Builder方法不能
如:todolist,需要给每个待办事项都定义一个状态变量,此时只能用自定义组件实现。
@BuilderParam
用于装饰自定义组件(struct)中的属性,其装饰的属性可作为一个UI结构的占位符;
创建该组件时,可通过参数为其传入具体的内容(类似于Vue中的slot)
@Component
struct Child {
// 使用父组件@Builder装饰的方法初始化子组件@BuilderParam
@BuilderParam customBuilderParam: () => void;
build() {
Column() {
this.customBuilderParam()
}
}
}
@Entry
@Component
struct Parent {
@Builder componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
Child({ customBuilderParam: this.componentBuilder })
}
}
}
状态管理
@State
用于修饰当前组件的状态变量,@State修饰的变量发生改变时,会驱动当前组件的试图刷新
@State修饰的变量必须进行本地初始化
@State count:number = 0
1、@State允许修饰的变量类型有string、number、boolean、object、enum、class
2、框架能够观察到的变化,不是@state变量的所有更改都会引起UI的刷新,只有可以被框架观察到的修改才会引起UI的刷新:boolean、string、number
3、@State修饰的变量为class和Object时,可以观察到变量自身赋值的变化,嵌套属性的变化是观察不到的
4、当@State装饰的变量为数组时,可以观察到元素本身赋值、元素添加、删除及更新的变化,若元素类型为class/object时,元素属性的变化时观察不到的
**变量为class/Object/数组时框架仅能观察到@State变量第一层属性的变化
@Prop
除了与@State相同的作用外,@Prop装饰的变量还可以同步父组件中的状态变量,且只能单向同步,子组件的变化不会同步到父组件
目前只支持简单数据类型:string/number/boolean/enum
@prop装饰的变量不允许初始化,只能通过父组件向子组件传参进行初始化
struct Parent{
@State count:number = 1
build() {
Column(){
Child({count:$count})
}
}
}
@Component
struct Child{
@Prop count:number
build() {
Text(this.count.toString())
}
}
@Link
除了与@State相同的作用外,@Link同样会同步父组件状态,并且能够双向同步
@Link装饰的变量不允许本地初始化,只能由父组件通过传参进行初始化,父组件必须使用$变量名的方式传参
struct Parent{
@State count:number = 1
build() {
Column(){
Child({count:$count})
}
}
}
@Component
struct Child{
@Link count:number
build() {
Text(this.count.toString())
}
}
@Provide和@Conmuse
可用于跨组件层级传递状态信息
其中,@Provide用于装饰祖先组件的状态变量,@Conmuse用于修饰后代组件的状态变量。
祖先组件提供Provide状态信息供后代组件消费,
并且祖先和后代的状态信息可双向同步
@Provide装饰变量必须进行本地初始化,而@Conmuse装饰的变量不允许进行本地初始化
struct GrandParent{
@Provide count:number = 1
// 别名
// @Provide('count') ParentContent:number = 1
build() {
Column(){
Parent()
}
}
}
@Component
struct Parent{
build(){
Column(){
Child()
}
}
}
@Component
struct Child{
@Consume count:number;
// 通过变量的别名进行绑定
// @Consume('count') childCount:number
build() {
Column(){
Text(this.count.toString())
}
}
}
@ObjectLink和@Observed
解决只能观察到第一层属性变化的问题
修改嵌套对象写法会让页面刷新,需要重新赋值整个项,才能检测到变化,使页面重新刷新,降低用户体验。