HarmonyOS 组件样式@Style 、 @Extend、自定义扩展(AttributeModifier、AttributeUpdater)

1. HarmonyOS @Style 、 @Extend、自定义扩展(AttributeModifier、AttributeUpdater)

  @Styles装饰器:定义组件重用样式
  ;@Extend装饰器:定义扩展组件样式
  自定义扩展:AttributeModifier、AttributeUpdater

1.1. 区别

1.1.1. 对比

  声明式语法引入了@Styles和@Extend两个装饰器,可以解决部分复用的问题,但是存在以下受限场景:
  (1)@Styles和@Extend均是编译期处理,不支持跨文件的导出复用。
  (2)@Styles仅能支持通用属性、事件,不支持组件特有的属性。
  (3)@Styles虽然支持在多态样式下使用,但不支持传参,无法对外开放一些属性。
  (4)@Extend虽然能支持特定组件的私有属性、事件,但同样不支持跨文件导出复用。
  (5)@Styles、@Extend对于属性设置,无法支持业务逻辑编写,动态决定是否设置某些属性。只能通过三元表达式对所有可能设置的属性进行全量设置,设置大量属性时效率低下。
  (为了解决上述问题,ArkUI引入了AttributeModifier的机制,可以通过Modifier对象动态修改属性。能力对比如下:

项目@Styles@ExtendAttributeModifier
跨文件导出不支持不支持支持
通用属性设置支持支持支持
通用事件设置支持支持部分支持
组件特有属性设置不支持支持部分支持
组件特有事件设置不支持支持部分支持
参数传递不支持支持支持
多态样式支持不支持支持
业务逻辑不支持不支持支持

  可以看出,AttributeModifier的能力和灵活性更好,当前持续在构建全量的属性、事件设置能力。未来,AttributeModifier可以替代@Styles和@Extend几乎所有的能力,建议上述场景都使用AttributeModifier。

1.1.2. @Style 和 @Extend 是否支持export导出

  方舟UI框架(ArkUI)解答文档
  (1)@Styles或@Extend目前不支持export导出,后续这两个装饰器不会继续演进。
  (2)推荐开发者使用新的样式复用方法,通过attributeModifier属性动态的设置组件,通过自定义class继承对应基础组件的Modifier,在class中设置复用的属性,对应class也没有无法export的限制。但是attributeModifier的复用能力仍有缺陷,目前不支持事件手势,这两个能力已有需求跟踪。
在这里插入图片描述

1.2. @Styles装饰器:定义组件重用样式

  如果每个组件的样式都需要单独设置,在开发过程中会出现大量代码在进行重复样式设置,虽然可以复制粘贴,但为了代码简洁性和后续方便维护,我们推出了可以提炼公共样式进行复用的装饰器@Styles。
  @Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位置调用。通过@Styles装饰器可以快速定义并复用自定义样式。
  说明:
  从API version 9开始,该装饰器支持在ArkTS卡片中使用。
  从API version 11开始,该装饰器支持在元服务中使用。

1.2.1. 装饰器使用说明

  (1)当前@Styles仅支持通用属性和通用事件。
  @Styles方法不支持参数,反例如下。

// 反例: @Styles不支持参数
@Styles function globalFancy (value: number) {.width(value)
}

  (2)@Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。
  说明
  只能在当前文件内使用,不支持export。
  如果想实现export功能,推荐使用AttributeModifier

// 全局
@Styles function functionName() { ... }// 在组件内
@Component
struct FancyUse {@Styles fancy() {.height(100)}
}

  (3)如果要实现跨文件操作的功能,可以参考使用动态属性设置。

// index.ets
import { MyButtonModifier } from './setAttribute'@Entry
@Component
struct attributeDemo {@State modifier: MyButtonModifier = new MyButtonModifier()build() {Row() {Column() {Button("Button").attributeModifier(this.modifier).onClick(() => {this.modifier.isDark = !this.modifier.isDark})}.width('100%')}.height('100%')}
}
// setAttribute.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {isDark: boolean = falseapplyNormalAttribute(instance: ButtonAttribute): void {if (this.isDark) {instance.backgroundColor(Color.Black)} else {instance.backgroundColor(Color.Red)}}
}

  (4)定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过事件来改变状态变量的值,示例如下:

@Component
struct FancyUse {@State heightValue: number = 100@Styles fancy() {.height(this.heightValue).backgroundColor(Color.Yellow).onClick(() => {this.heightValue = 200})}
}

  (5)组件内@Styles的优先级高于全局@Styles。
  框架优先找当前组件内的@Styles,如果找不到,则会全局查找。

1.2.2. 使用场景

  以下示例中演示了组件内@Styles和全局@Styles的用法。

import { TitleBar } from '../../components/common/TitleBar'
import { router } from '@kit.ArkUI'
import { RouterParams } from 'zzslib'/*** @Styles可以定义在组件内、外*/
/*** 组件外* 在组件外定义时需带上function关键字*/
@Styles
function styleGlobal() {.backgroundColor(Color.Red).width(100).height(100)
}@Styles
function styleGlobal2() {// .backgroundColor(color).width(100).height(100)
}@Entry
@Component
struct StylePage {@State pageTitle: string = "网格列表"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}/*** 组件内* 在组件外定义时不需要带function关键字*/@StylesstyleFancy() {.backgroundColor(Color.Blue).width(100).height(100)}build() {Column() {TitleBar({ pageTitle: $pageTitle })Text("组件外样式").styleGlobal().fontSize(30)Text("组件内样式").styleFancy().fontSize(30)//@Styles还可以在StateStyles属性内部使用,// 在组件处于不同的状态时赋予相应的属性。//在StateStyles内可以直接调用组件外定义的Styles,// 但需要通过this关键字调用组件内定义的Styles。Button() {Text("StateStyles")}.stateStyles({normal: {.width(180).height(180)},disabled: this.styleFancy,pressed: styleGlobal})}}
}

在这里插入图片描述

1.3. @Extend 扩展原生组件样式

  @Extend,用于扩展原生组件样式
  说明:
  从API version 9开始,该装饰器支持在ArkTS卡片中使用。
  从API version 11开始,该装饰器支持在元服务中使用。

1.3.1. 装饰器使用说明

1.3.1.1. 语法
@Extend(UIComponentName) function functionName { ... }
1.3.1.2. 使用规则

  (1)和@Styles不同,@Extend仅支持在全局定义,不支持在组件内部定义。
  说明
  只能在当前文件内使用,不支持export
  如果想实现export功能,推荐使用AttributeModifier
  (2)和@Styles不同,@Extend支持封装指定组件的私有属性、私有事件和自身定义的全局方法。

// @Extend(Text)可以支持Text的私有属性fontColor
@Extend(Text) function fancy () {.fontColor(Color.Red)
}
// superFancyText可以调用预定义的fancy
@Extend(Text) function superFancyText(size:number) {.fontSize(size).fancy()
}

  (3)和@Styles不同,@Extend装饰的方法支持参数,开发者可以在调用时传递参数,调用遵循TS方法传值调用。

// xxx.ets
@Extend(Text) function fancy (fontSize: number) {.fontColor(Color.Red).fontSize(fontSize)
}@Entry
@Component
struct FancyUse {build() {Row({ space: 10 }) {Text('Fancy').fancy(16)Text('Fancy').fancy(24)}}
}

  (4)@Extend装饰的方法的参数可以为function,作为Event事件的句柄。

@Extend(Text) function makeMeClick(onClick: () => void) {.backgroundColor(Color.Blue).onClick(onClick)
}
@Entry
@Component
struct FancyUse {@State label: string = 'Hello World';onClickHandler() {this.label = 'Hello ArkUI';}build() {Row({ space: 10 }) {Text(`${this.label}`).makeMeClick(() => {this.onClickHandler()})}}
}

  (5)@Extend的参数可以为状态变量,当状态变量改变时,UI可以正常的被刷新渲染。

@Extend(Text) function fancy (fontSize: number) {.fontColor(Color.Red).fontSize(fontSize)
}@Entry
@Component
struct FancyUse {@State fontSizeValue: number = 20build() {Row({ space: 10 }) {Text('Fancy').fancy(this.fontSizeValue).onClick(() => {this.fontSizeValue = 30})}}
}

1.3.2. 使用场景

  通过@Extend组合样式后,使得代码更加简洁,增强可读性。

import { router } from '@kit.ArkUI'
import { RouterParams } from 'zzslib'
import { TitleBar } from '../../components/common/TitleBar'@Extend(Text)
function extendText() {.fontSize(15).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }).margin({top: 20,right: 20,bottom: 20,left: 20}).padding(20).border({width: {left: 1,right: 1,top: 1,bottom: 1},color: {left: Color.Blue,right: Color.Blue,top: Color.Red,bottom: $r('app.color.primary_font_content')},radius: {topLeft: 0,topRight: 0,bottomLeft: 0,bottomRight: 0},style: {left: BorderStyle.Dotted,right: BorderStyle.Dotted,top: BorderStyle.Solid,bottom: BorderStyle.Solid}})
}// @Extend(Text)可以支持Text的私有属性fontColor
@Extend(Text)
function fancy() {.fontColor(Color.Red)
}// superFancyText可以调用预定义的fancy
@Extend(Text)
function superFancyText(size: number) {.fontSize(size).fancy()
}@Extend(Text)
function extendTextLine(fontSize: number) {.fontSize(fontSize).fontColor($r('app.color.primary_font_title')).maxLines(1).margin({ top: 20 })
}@Entry
@Component
struct ExtendPage {@State pageTitle: string = "Extend"aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })Text('全局样式').extendText()Text('私有事件和自身定义的全局方法').superFancyText(20)Text('@Extend装饰传递参数').extendTextLine(20)}}
}

在这里插入图片描述

1.4. AttributeModifier

  声明式语法引入了@Styles和@Extend两个装饰器,可以解决部分复用的问题,但是存在以下受限场景,为此,ArkUI引入了AttributeModifier的机制,可以通过Modifier对象动态修改属性。AttributeModifier的能力和灵活性更好,当前持续在构建全量的属性、事件设置能力。未来,AttributeModifier可以替代@Styles和@Extend几乎所有的能力,建议上述场景都使用AttributeModifier。

1.4.1.接口定义

declare interface AttributeModifier<T> {applyNormalAttribute?(instance: T): void;applyPressedAttribute?(instance: T): void;applyFocusedAttribute?(instance: T): void;applyDisabledAttribute?(instance: T): void;applySelectedAttribute?(instance: T): void;}

  AttributeModifier是一个接口,需要开发者实现ApplyXxxAttribute的方法。Xxx表示多态的场景,支持默认态、按压态、焦点态、禁用态、选择态。其中,T是组件的属性类型,开发者可以在回调中获取到属性对象,通过该对象设置属性。

declare class CommonMethod<T> {attributeModifier(modifier: AttributeModifier<T>): T;
}
}

  在组件的通用方法上,增加了attributeModifier传入自定义的Modifier。由于组件在实例化时会明确T的类型,所以调用该方法时,T必须是组件对应的Attribute类型,或者是CommonAttribute。

1.4.2. 行为规格

  (1)组件通用方法attributeModifier支持传入一个实现AttributeModifier接口的实例,T必须是组件对应的Attribute类型,或者是CommonAttribute。
  (2)在组件首次初始化或者关联的状态变量发生变化时,如果传入的实例实现了对应接口,会触发applyNormalAttribute。
  (3)回调applyNormalAttribute时,会传入组件属性对象,通过该对象可以设置当前组件的属性/事件。
暂未支持的属性/事件,执行时会抛异常。
  (4)属性变化触发ApplyXxxAttribute函数时,该组件之前已设置的属性,在本次变化后未设置的属性会恢复为属性的默认值。
  (5)可以通过该接口使用多态样式的功能,例如如果需要在组件进入按压态时设置某些属性,就可以通过自定义实现applyPressedAttribute方法完成。
  (6)一个组件上同时使用属性方法和applyNormalAttribute设置相同的属性,遵循属性覆盖原则,即后设置的属性生效。
  (7)一个Modifier实例对象可以在多个组件上使用。
  (8)一个组件上多次使用applyNormalAttribute设置不同的Modifier实例,每次状态变量刷新均会按顺序执行这些实例的方法属性设置,同样遵循属性覆盖原则。

1.4.3. 属性设置与修改

  AttributeModifier可以分离UI与样式,支持参数传递及业务逻辑编写,并且通过状态变量触发刷新。

// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {// 可以实现一个Modifier,定义私有的成员变量,外部可动态修改isDark: boolean = false// 通过构造函数,创建时传参constructor(dark?: boolean) {this.isDark = dark ? dark : false}applyNormalAttribute(instance: ButtonAttribute): void {// instance为Button的属性对象,可以通过instance对象对属性进行修改if (this.isDark) { // 支持业务逻辑的编写// 属性变化触发apply函数时,变化前已设置并且变化后未设置的属性会恢复为默认值instance.backgroundColor(Color.Black)} else {// 支持属性的链式调用instance.backgroundColor(Color.Red).borderColor(Color.Black).borderWidth(2)}}
}
// demo.ets
import { MyButtonModifier } from './button_modifier'@Entry
@Component
struct attributeDemo {// 支持用状态装饰器修饰,行为和普通的对象一致@State modifier: MyButtonModifier = new MyButtonModifier(true);build() {Row() {Column() {Button("Button").attributeModifier(this.modifier).onClick(() => {// 对象的一层属性被修改时,会触发UI刷新,重新执行applyNormalAttributethis.modifier.isDark = !this.modifier.isDark})}.width('100%')}.height('100%')}
}

  一个组件上同时使用属性方法和applyNormalAttribute设置相同的属性,遵循属性覆盖原则,即后设置的属性生效。

// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {isDark: boolean = falseconstructor(dark?: boolean) {this.isDark = dark ? dark : false}applyNormalAttribute(instance: ButtonAttribute): void {if (this.isDark) {instance.backgroundColor(Color.Black)} else {instance.backgroundColor(Color.Red).borderColor(Color.Black).borderWidth(2)}}
}
// demo.ets
import { MyButtonModifier } from './button_modifier';@Entry
@Component
struct attributeDemo {@State modifier: MyButtonModifier = new MyButtonModifier(true);build() {Row() {Column() {// 先设置属性,后设置modifier,按钮颜色会跟随modifier的值改变Button("Button").backgroundColor(Color.Blue).attributeModifier(this.modifier).onClick(() => {this.modifier.isDark = !this.modifier.isDark})}.width('100%')}.height('100%')}
}

  一个组件上多次使用applyNormalAttribute设置不同的Modifier实例,每次状态变量刷新均会按顺序执行这些实例的方法属性设置,遵循属性覆盖原则,即后设置的属性生效。

// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {isDark: boolean = falseconstructor(dark?: boolean) {this.isDark = dark ? dark : false}applyNormalAttribute(instance: ButtonAttribute): void {if (this.isDark) {instance.backgroundColor(Color.Black).width(200)} else {instance.backgroundColor(Color.Red).width(100)}}
}
// button_modifier2.ets
export class MyButtonModifier2 implements AttributeModifier<ButtonAttribute> {isDark2: boolean = falseconstructor(dark?: boolean) {this.isDark2 = dark ? dark : false}applyNormalAttribute(instance: ButtonAttribute): void {if (this.isDark2) {instance.backgroundColor('#2787D9')} else {instance.backgroundColor('#707070')}}
}
// demo.ets
import { MyButtonModifier } from './button_modifier';
import { MyButtonModifier2 } from './button_modifier2';@Entry
@Component
struct attributeDemo {@State modifier: MyButtonModifier = new MyButtonModifier(true);@State modifier2: MyButtonModifier2 = new MyButtonModifier2(true);build() {Row() {Column() {Button("Button").attributeModifier(this.modifier).attributeModifier(this.modifier2).onClick(() => {this.modifier.isDark = !this.modifier.isDarkthis.modifier2.isDark2 = !this.modifier2.isDark2})}.width('100%')}.height('100%')}
}

1.4.4. 设置多态样式、事件

  使用AttributeModifier设置多态样式、事件,实现事件逻辑的复用,支持默认态、按压态、焦点态、禁用态、选择态。例如如果需要在组件进入按压态时设置某些属性,就可以通过自定义实现applyPressedAttribute方法完成。

// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {applyNormalAttribute(instance: ButtonAttribute): void {// instance为Button的属性对象,设置正常状态下属性值instance.backgroundColor(Color.Red).borderColor(Color.Black).borderWidth(2)}applyPressedAttribute(instance: ButtonAttribute): void {// instance为Button的属性对象,设置按压状态下属性值instance.backgroundColor(Color.Green).borderColor(Color.Orange).borderWidth(5)}
}
// demo.ets
import { MyButtonModifier } from './button_modifier'@Entry
@Component
struct attributeDemo {@State modifier: MyButtonModifier = new MyButtonModifier();build() {Row() {Column() {Button("Button").attributeModifier(this.modifier)}.width('100%')}.height('100%')}
}

1.4.5. 示例

import { CommonModifier, router } from '@kit.ArkUI'
import { RouterParams } from 'zzslib'
import { TitleBar } from '../../components/common/TitleBar'class MyButtonModifier implements AttributeModifier<ButtonAttribute> {isDark: boolean = false// applyNormalAttribute(instance: ButtonAttribute): void {//   if (this.isDark) {//     instance.backgroundColor(Color.Black)//   } else {//     instance.backgroundColor(Color.Red)//   }// }/*** 组件普通状态时的样式* @param instance*/applyNormalAttribute(instance: ButtonAttribute): void {instance.backgroundColor(Color.Black)}/*** 组件按压状态的样式* @param instance*/applyPressedAttribute(instance: ButtonAttribute): void {instance.backgroundColor(Color.Red)}/*** 组件禁用状态的样式* @param instance*/applyDisabledAttribute(instance: ButtonAttribute): void {}/*** 组件选中状态的样式* @param instance*/applySelectedAttribute(instance: ButtonAttribute): void {}
}class MyModifier extends CommonModifier {applyNormalAttribute(instance: CommonAttribute): void {super.applyNormalAttribute?.(instance);}public setGroup1(): void {this.borderStyle(BorderStyle.Dotted)this.borderWidth(8)}public setGroup2(): void {this.borderStyle(BorderStyle.Dashed)this.borderWidth(8)}
}@Component
struct MyImage1 {@Link modifier: CommonModifierbuild() {Image($r("app.media.icon_main_apply_normal")).attributeModifier(this.modifier as MyModifier)}
}/*** 设置自定义Modifier给一个组件,该组件对应属性生效。* 自定义Modifier属性值变化,组件对应属性也会变化。自定义Modifier类型为基类,* 构造的对象为子类对象,使用时要通过as进行类型断言为子类。* 一个自定义Modifier设置给两个组件,Modifier属性变化的时候对两个组件同时生效。* 一个Modifier设置了属性A和属性B,再设置属性C和属性D,4个属性同时在组件上生效。* 自定义Modifier不支持@State标注的状态数据的变化感知,见示例2。* 多次通过attributeModifier设置属性时,生效的属性为所有属性的并集,相同属性按照设置顺序生效。*/
@Entry
@Component
struct AttributeModifierPage {@State pageTitle: string = "自定义样式"@State modifier: MyButtonModifier = new MyButtonModifier()@State myModifier: CommonModifier = new MyModifier().width(100).height(100).margin(10)index: number = 0;aboutToAppear() {try {this.pageTitle = (router.getParams() as RouterParams).title} catch (e) {}}build() {Column() {TitleBar({ pageTitle: $pageTitle })Column() {// Button("Button")//   .attributeModifier(this.modifier)//   .onClick(() => {//     this.modifier.isDark = !this.modifier.isDark//   })Button("Button").attributeModifier(this.modifier)Button($r("app.string.EntryAbility_label")).margin(10).onClick(() => {console.log("Modifier", "onClick")this.index++;if (this.index % 2 === 1) {(this.myModifier as MyModifier).setGroup1()console.log("Modifier", "setGroup1")} else {(this.myModifier as MyModifier).setGroup2()console.log("Modifier", "setGroup2")}})MyImage1({ modifier: this.myModifier })}.width('100%')}.height('100%')}
}

在这里插入图片描述

1.5. AttributeUpdater

1.5.1. 概述

  大量属性频繁更新时,如果使用状态变量,会导致前端状态管理计算量太大,并需要对单个组件进行全量的属性更新。虽然可以通过AttributeModifier的机制按需更新,但是前端还是默认会有一些diff和reset的策略。
  为此引入了AttributeUpdater的能力,它是一个特殊的AttributeModifier,除了继承AttributeModifier的能力,还提供了获取属性对象的能力。通过属性对象可以不经过状态变量,直接更新对应属性。使用AttributeUpdater,开发者可实现自定义的更新策略,进一步提高属性更新的性能。但是由于该能力比较灵活,无法限制“单一数据源”的规则,同时和状态变量更新相同属性时,存在相互覆盖的情况,需要开发者自己保障属性设置的合理性。

1.5.2. 接口定义

export declare class AttributeUpdater<T, C = Initializer<T>> implements AttributeModifier<T> {applyNormalAttribute?(instance: T): void;initializeModifier(instance: T): void;get attribute(): T | undefined;updateConstructorParams: C;
}

  AttributeUpdater实现了AttributeModifier接口,额外提供了initializeModifier,可以对组件的属性进行初始化,并且通过attribute属性方法,获取到属性对象,通过该对象直接更新对应组件的属性。另外也可以直接通过updateConstructorParams更新组件的构造参数。

1.5.3. 行为规格

  (1)开发者可以实现一个AttributeUpdater的类,并通过组件的AttributeModifier设置,首次绑定时会触发initializeModifier方法,进行属性的初始化,后续其它的生命周期和AttributeModifier保持一致。
  (2)组件初始化完成之后,可以通过AttributeUpdater实例的attribute属性方法,获取到属性对象,否则为undefined。
  (3)通过attribute属性对象直接修改属性,会将最新设置的属性记录在当前对象中,并立即触发组件属性的更新。
  (4)如果将AttributeUpdater实例标记为状态变量进行修改,或者通过其它状态变量更新对应组件的属性,会触发applyNormalAttribute的流程,如果开发者没有覆写该逻辑,默认会将属性对象记录的所有属性,批量进行一次更新。
  (5)如果开发者复写applyNormalAttribute的逻辑,并且不调用super的该方法,将会失去获取attribute属性对象的能力,不会调用initializeModifier方法。
  (6)一个AttributeUpdater对象只能同时关联一个组件,否则只会有一个组件生效属性设置。

1.5.4. 通过modifier直接修改属性

  组件初始化完成之后,可以通过AttributeUpdater实例的attribute属性方法,获取到属性对象,通过属性对象直接修改属性,会立即触发组件属性的更新。

import { AttributeUpdater } from '@ohos.arkui.modifier'class MyButtonModifier extends AttributeUpdater<ButtonAttribute> {initializeModifier(instance: ButtonAttribute): void {instance.backgroundColor('#2787D9').width('50%').height(30)}
}@Entry
@Component
struct updaterDemo {modifier: MyButtonModifier = new MyButtonModifier()build() {Row() {Column() {Button("Button").attributeModifier(this.modifier).onClick(() => {this.modifier.attribute?.backgroundColor('#17A98D').width('30%')})}.width('100%')}.height('100%')}
}

1.5.4. 通过modifier更新组件的构造参数

  可以直接通过AttributeUpdater实例的updateConstructorParams方法,更新组件的构造参数。

import { AttributeUpdater } from '@ohos.arkui.modifier'class MyTextModifier extends AttributeUpdater<TextAttribute, TextInterface> {initializeModifier(instance: TextAttribute): void {}
}@Entry
@Component
struct updaterDemo {modifier: MyTextModifier = new MyTextModifier()build() {Row() {Column() {Text("Text").attributeModifier(this.modifier).fontColor(Color.White).fontSize(14).border({ width: 1 }).textAlign(TextAlign.Center).lineHeight(20).width(200).height(50).backgroundColor('#2787D9').onClick(() => {this.modifier.updateConstructorParams('Update');})}.width('100%')}.height('100%')}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/56820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 下的Excel文件损坏与内容乱码问题

序言 随着打包部署的方式的改变&#xff0c;原本正常运行的代码可能带来一些新的问题&#xff0c;比如我们现在使用SpringBoot 的方式生成Jar包直接运行&#xff0c;就会对我们再在Resource下的Excel文件产生影响&#xff0c;导入与预期不符的情况发生cuiyaonan2000163.com 比…

Anchor DETR论文笔记

原文链接 [2109.07107] Anchor DETR: Query Design for Transformer-Based Object Detection (arxiv.org)https://arxiv.org/abs/2109.07107 原文笔记 What 提出了一种新的基于锚点的查询设计&#xff0c;即将锚点编码为对象查询。 Why 对象检测任务是预测图像中每个对象…

el-table相关的功能实现

1. 表格嵌套表格时&#xff0c;隐藏父表格的全选框 场景&#xff1a;当table表格设置复选&#xff08;多选&#xff09;功能时&#xff0c;如何隐藏表头的复选框&#xff0c;不让用户一键多选。 <el-table :header-cell-class-name"cellClass">// 表头复选框禁…

机器视觉-相机、镜头、光源(总结)

目录 1、机器视觉光源概述 2、光源的作用 3、光谱 4、工业场景常见光源 4.1、白炽灯 4.2、卤素灯 4.3、 荧光灯 4.4、LED灯 4.5、激光灯 5、光源的基本性能 5.1、光通量 5.2、光效率 5.3、发光强度 5.4、光照度 5.5、均匀性 5.6、色温 5.7、显色性 6、基本光学…

【Linux | 网络I/O模型】五种网络I/O模型详解

1、数据传输过程 在 Linux 系统中&#xff0c;数据传输是通过 I/O 操作来实现的。I/O 操作是指数据从应用程序到内核&#xff0c;再到硬件设备&#xff08;如磁盘、网络接口&#xff09;的过程。 操作系统为了保护自己&#xff0c;设计了用户态、内核态两个状态。应用程序一般工…

基于云平台的智能家居管理系统设计与通信协议分析

案例 阅读以下关于 Web 系统架构设计的教述&#xff0c;在答题纸上回答问题1至问题3。 【说明】 某公司拟开发一个智能家居管理系统&#xff0c;该系统的主要功能需求如下: 1)用户可使用该系统客户端实现对家居设备的控制&#xff0c;且家居设备可向客户端反馈实时状态&#x…

Redis 线程控制 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 线程控制 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 线程控制 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis &a…

JavaScript part2

一.前言 前面我们讲了一下js的基础语法&#xff0c;但是这些还是远远不够的&#xff0c;我们要想操作标签&#xff0c;实现一个动态且好看的页面&#xff0c;就得学会BOM和DOM&#xff0c;这些都是浏览器和页面的&#xff0c;这样我们才能实现一个好看的页面 二.BOM对象 BOM…

Radar Fields: Frequency-Space Neural Scene Representations for FMCW Radar 笔记

Code 主要思想 文章提出了一种新的神经场表示方法——Radar Fields&#xff0c;用于从FMCW&#xff08;调频连续波&#xff09;雷达数据中恢复场景几何信息。与以往的依赖于光学成像&#xff08;如RGB相机和LiDAR&#xff09;的神经场方法不同&#xff0c;该研究利用了雷达的…

高级网络互联技术:AS3001与AS3000的路由交换方案

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

基于SSM的智能养生平台管理系统源码带本地搭建教程

技术栈与架构 技术框架&#xff1a;采用SSM&#xff08;Spring Spring MVC MyBatis&#xff09;作为后端开发框架&#xff0c;结合前端技术栈layui、JSP、Bootstrap与jQuery&#xff0c;以及数据库MySQL 5.7&#xff0c;共同构建项目。 运行环境&#xff1a;项目在JDK 8环境…

HarmonyOS 5.0应用开发——应用打包HAP、HAR、HSP

【高心星出品】 目录 应用打包HAP、HAR、HSPModule类型HAPHAR创建HAR建立依赖HAR共享内容 HSP创建HSP建立依赖同上HSP共享内容同上 HAR VS HSP 应用打包HAP、HAR、HSP 一个应用通常会包含多种功能&#xff0c;将不同的功能特性按模块来划分和管理是一种良好的设计方式。在开发…

【mysql】4-2. MySQL存储结构

MySQL存储结构 1 什么是表空间⽂件&#xff1f; 解答问题 表空间⽂件是⽤来存储表中数据的⽂件&#xff0c;表空间⽂件的⼤⼩由存储的数据多少决定&#xff0c;不同的表空间⽂件存储数据的种类也有所不同&#xff0c;在MySQL中表空间分为五类&#xff0c;包括&#xff1a;系统…

Python | Leetcode Python题解之第514题自由之路

题目&#xff1a; 题解&#xff1a; Test "godding" target "d"i 0left i lc 0 right i rc 0while Test[left] ! target:left - 1lc 1if left -1:left len(Test) - 1while Test[right] ! target:right 1rc 1if right len(Test):right 0prin…

vue3报错:找不到模块“element-plus”或其相应的类型说明

1.问题复现 2.首先去检查一下package.json中是否安装了element-plus 3.存在&#xff0c;就是另一个问题&#xff0c;模块没有被导出来 a.此时需要建立一个.d.ts文件&#xff08;在package.json同级目录下&#xff09; 4.写入代码保存&#xff0c;即可解决报错问题 declare mo…

安卓在windows连不上fastboot问题记录

fastboot在windows连不上fastboot 前提是android studio安装 google usb driver 搜索设备管理器 插拔几次找安卓设备 在其他设备 或者串行总线设备会出现安卓 右键更新驱动 下一步下一步然后可以了

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21目录1. The Fair Language Model Paradox摘要研究背景问题与挑战如何解决创新点算法模型实验效果重要数据与结论推荐阅读指数&…

海外媒体发稿:如何打造媒体发稿策略

新闻媒体的发稿推广策略对于提升品牌知名度、吸引流量以及增加收入非常重要。本文将介绍一套在21天内打造爆款新闻媒体发稿推广策略的方法。 第一天至第七天&#xff1a;明确目标和定位 在这个阶段&#xff0c;你需要明确你的目标和定位&#xff0c;以便为你的新闻媒体建立一个…

群晖系统基本命令

切换超级管理员 sudo -i 查询系统 运行的所有服务 synoservicecfg --list 启动服务命令(该命令需要使用超级管理员) #老版本群晖使用synoservice命令 synoservice --start 服务名称#新版本群晖使用systemctl命令 systemctl start 服务名称 synoservice所管理的服务配置文…

Spring Cloud微服务

Spring Cloud 是一个专注于微服务架构的一站式解决方案&#xff0c;它通过整合多个优秀的开源框架和工具&#xff0c;为开发者提供了构建、管理和维护微服务系统所需的全方位支持。以下是关于 Spring Cloud 微服务的详细介绍&#xff1a; 基本概念 微服务架构&#xff1a;微服务…