HarmonyOS:@Builder装饰器:自定义构建函数

一、前言

ArkUI提供了一种轻量的UI元素复用机制@Builder,其内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。

为了简化语言,我们将@Builder装饰的函数也称为“自定义构建函数”。

说明
从API version 9开始,该装饰器支持在ArkTS卡片中使用。

从API version 11开始,该装饰器支持在元服务中使用。

二、装饰器使用说明

2.1 私有自定义构建函数

定义的语法:

@Builder MyBuilderFunction() {}

使用方法:

this.MyBuilderFunction()
  • 允许在自定义组件内定义一个或多个@Builder方法,该方法被认为是该组件的私有、特殊类型的成员函数。
  • 私有自定义构建函数允许在自定义组件内、build方法和其他自定义构建函数中调用。
  • 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。
2.2 全局自定义构建函数

定义的语法:

@Builder function MyGlobalBuilderFunction() { ... }

使用方法:

MyGlobalBuilderFunction()
  • 如果不涉及组件状态变化,建议使用全局的自定义构建方法。
  • 全局自定义构建函数允许在build方法和其他自定义构建函数中调用。

三、参数传递规则

自定义构建函数的参数传递有按值传递和按引用传递两种,均需遵守以下规则:

  • 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。
  • 在@Builder修饰的函数内部,不允许改变参数值。
  • @Builder内UI语法遵循UI语法规则。
  • 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。
3.1 按引用传递参数

按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。

class Tmp {paramA1: string = ''
}@Builder function overBuilder(params: Tmp) {Row() {Text(`UseStateVarByReference: ${params.paramA1} `)}
}@Entry
@Component
struct TestBuilder {@State label: string = 'Hello';build() {Column({space: 10}) {// 在父组件中调用overBuilder组件时,// 把this.label通过引用传递的方式传给overBuilder组件。overBuilder({ paramA1: this.label })Button('Click me').onClick(() => {// 单击Click me后,UI文本从Hello更改为ArkUI。this.label = 'ArkUI';})}.height('100%').width('100%')}
}

效果图

在这里插入图片描述

按引用传递参数时,如果在@Builder方法内调用自定义组件,ArkUI提供$$作为按引用传递参数的范式。


class Tmp {paramA1: string = ''
}// 按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。
@Builder
function overBuilder(params: Tmp) {Row() {Text(`UseStateVarByReference: ${params.paramA1} `)}
}// 按引用传递参数时,如果在@Builder方法内调用自定义组件,ArkUI提供$$作为按引用传递参数的范式。
@Builder
function overBuilder2($$: Tmp) {Column() {Text(`overBuilder2 ==${$$.paramA1}`)HelloComponent({ message: $$.paramA1 })}
}@Component
struct HelloComponent {@Prop message: stringbuild() {Column() {Text(`HelloComponent == ${this.message}`)}}
}@Entry
@Component
struct TestBuilder {@State label: string = 'Hello';build() {Column({ space: 10 }) {// 在父组件中调用overBuilder组件时,// 把this.label通过引用传递的方式传给overBuilder组件。// overBuilder({ paramA1: this.label })overBuilder2({ paramA1: this.label })Button('Click me').onClick(() => {// 单击Click me后,UI文本从Hello更改为ArkUI。this.label = 'ArkUI';})}.height('100%').width('100%')}
}

效果图

在这里插入图片描述

3.2 按值传递参数

调用@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递

/*
按值传递参数
调用@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递。*/
@Builder
function overBuilder3(params: string) {Column() {Text(`overBuilder3 UseStateVarByValue: ${params} `)}
}@Entry
@Component
struct TestBuilder {@State label: string = 'Hello';build() {Column({ space: 10 }) {// 在父组件中调用overBuilder组件时,// 把this.label通过引用传递的方式传给overBuilder组件。// overBuilder({ paramA1: this.label })// overBuilder2({ paramA1: this.label })overBuilder3(this.label)Button('Click me').onClick(() => {// 单击Click me后,UI文本从Hello更改为ArkUI。this.label = 'ArkUI';console.log("点击了Click事件")})}.height('100%').width('100%')}
}

效果图

在这里插入图片描述

使用按值传递的方式,在@ComponentV2装饰器修饰的自定义组件里配合使用@ObservedV2和@Trace装饰器可以实现刷新UI功能。

【正例】

在@ComponentV2装饰中,只有使用@ObservedV2修饰的ParamTmp类和@Trace修饰的count属性才可以触发UI的刷新。

@ObservedV2
class ParamTmp {@Trace count : number = 0;
}@Builder
function renderText(param: ParamTmp) {Column() {Text(`param : ${param.count}`).fontSize(20).fontWeight(FontWeight.Bold)}
}@Builder
function renderMap(paramMap: Map<string,number>) {Text(`paramMap : ${paramMap.get('name')}`).fontSize(20).fontWeight(FontWeight.Bold)
}@Builder
function renderSet(paramSet: Set<number>) {Text(`paramSet : ${paramSet.size}`).fontSize(20).fontWeight(FontWeight.Bold)
}@Builder
function renderNumberArr(paramNumArr: number[]) {Text(`paramNumArr : ${paramNumArr[0]}`).fontSize(20).fontWeight(FontWeight.Bold)
}@Entry
@ComponentV2
struct TestBuilder2{@Local builderParams: ParamTmp = new ParamTmp();@Local map_value: Map<string,number> = new Map();@Local set_value: Set<number> = new Set([0]);@Local numArr_value: number[] = [0];private progressTimer: number = -1;aboutToAppear(): void {this.progressTimer = setInterval(() => {if (this.builderParams.count < 100) {this.builderParams.count += 5;this.map_value.set('name', this.builderParams.count);this.set_value.add(this.builderParams.count);this.numArr_value[0] = this.builderParams.count;} else {clearInterval(this.progressTimer)}}, 500);}@BuilderlocalBuilder() {Column() {Text(`localBuilder : ${this.builderParams.count}`).fontSize(20).fontWeight(FontWeight.Bold)}}build() {Column() {this.localBuilder()Text(`builderParams :${this.builderParams.count}`).fontSize(20).fontWeight(FontWeight.Bold)renderText(this.builderParams)renderText({ count: this.builderParams.count })renderMap(this.map_value)renderSet(this.set_value)renderNumberArr(this.numArr_value)}.width('100%').height('100%')}
}

效果图

在这里插入图片描述

在这里插入图片描述


@ObservedV2
class ParamTmp2 {@Trace count : number = 0;
}@Builder
function renderNumber(paramNum: number) {Text(`paramNum : ${paramNum}`).fontSize(30).fontWeight(FontWeight.Bold)
}@Entry
@ComponentV2
struct TestBuilder3 {@Local class_value: ParamTmp2 = new ParamTmp2();// 此处使用简单数据类型不支持刷新UI的能力。@Local num_value: number = 0;private progressTimer: number = -1;aboutToAppear(): void {this.progressTimer = setInterval(() => {if (this.class_value.count < 100) {this.class_value.count += 5;this.num_value += 5;console.log(`this.num_value = ${this.num_value}`)} else {clearInterval(this.progressTimer)}}, 500);}build() {Column() {renderNumber(this.num_value)}.width('100%').height('100%').padding(50)}
}

效果图

在这里插入图片描述

四、限制条件

4.1 @Builder装饰的函数内部,不允许修改参数值,否则框架会抛出运行时错误。开发者可以在调用@Builder的自定义组件里改变其参数。

测试结果

在这里插入图片描述

在这里插入图片描述

  1. @Builder通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个。
  2. @Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI。
  3. @Builder传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI。
  4. @Builder的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI。

五、使用场景

5.1 自定义组件内使用自定义构建函数

创建私有的@Builder方法,在Column里面使用this.builder()方式调用,通过aboutToAppear生命周期函数和按钮的点击事件改变builder_value的内容,实现动态渲染UI。

@Entry
@Component
struct PrivateBuilder {@State builder_value: string = 'Hello';@Builderbuilder() {Column() {Text(this.builder_value).fontSize(30).fontWeight(FontWeight.Bold)}}aboutToAppear(): void {setTimeout(() => {this.builder_value = 'Hello World';}, 3000)}build() {Row() {Column({ space: 10 }) {Text(this.builder_value).fontSize(30).fontWeight(FontWeight.Bold)this.builder()Button('点击改变builder_value内容').onClick(() => {this.builder_value = 'builder_value被点击了'})}.padding(20)}}
}

效果图

在这里插入图片描述

5.2 使用全局自定义构建函数

创建全局的@Builder方法,在Column里面使用overBuilder()方式调用,通过以对象字面量的形式传递参数,无论是简单类型还是复杂类型,值的改变都会引起UI界面的刷新。

class ChildTmp5 {val: number = 1;
}class Tmp5 {str_value: string = 'Hello';num_value: number = 0;tmp_value: ChildTmp5 = new ChildTmp5();arrayTmp_value: Array<ChildTmp5> = [];
}@Builder
function overBuilder5(param: Tmp5) {Column() {Text(`str_value: ${param.str_value}`)Text(`num_value: ${param.num_value}`)Text(`tmp_value: ${param.tmp_value.val}`)ForEach(param.arrayTmp_value, (item: ChildTmp5) => {Text(`arrayTmp_value: ${item.val}`)}, (item: ChildTmp5) => JSON.stringify(item))}
}@Entry
@Component
struct TestBuilder5 {@State objParam: Tmp5 = new Tmp5();build() {Column({ space: 10 }) {Text('通过调用@Builder渲染UI界面').fontSize(20)overBuilder5({str_value: this.objParam.str_value,num_value: this.objParam.num_value,tmp_value: this.objParam.tmp_value,arrayTmp_value: this.objParam.arrayTmp_value})Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button('点击改变参数值').onClick(() => {this.objParam.str_value = 'Hello World';this.objParam.num_value = 1;this.objParam.tmp_value.val = 8;const child_value: ChildTmp5 = {val: 2}this.objParam.arrayTmp_value.push(child_value)})}}
}

效果图

在这里插入图片描述

5.3 修改装饰器修饰的变量触发UI刷新

此种方式是使用了装饰器的特性,监听值的改变触发UI刷新,不通过@Builder传递参数。

class Tmp6 {str_value: string = 'Hello';
}@Entry
@Component
struct TestBuilder6 {@State objParam: Tmp6 = new Tmp6();@State label: string = 'World';@Builder privateBuilder() {Column() {Text(`wrapBuilder str_value: ${this.objParam.str_value}`)Text(`wrapBuilder num: ${this.label}`)}}build() {Column() {Text('通过调用@Builder渲染UI界面').fontSize(20)this.privateBuilder()Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button('点击改变参数值').onClick(() => {this.objParam.str_value = 'str_value Hello World';this.label = 'label Hello World'})}}
}

效果图

在这里插入图片描述

5.4 使用全局和局部的@Builder传入customBuilder类型
@Builder
function overBuilder6() {Row() {Text('全局 Builder').fontSize(30).fontWeight(FontWeight.Bold)}
}@Entry
@Component
struct CustomBuilderDemo {@State arr: number[] = [0, 1, 2, 3, 4];@BuilderprivateBuilder() {Row() {Text('局部 Builder').fontSize(30).fontWeight(FontWeight.Bold)}}build() {Column() {List({ space: 10 }) {ForEach(this.arr, (item: number) => {ListItem() {Text(`${item}`).width('100%').height(100).fontSize(16).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)}.swipeAction({start: { builder: overBuilder6() },end: {builder: () => {this.privateBuilder()}}})}, (item: string) => JSON.stringify(item))}}}
}

效果图

在这里插入图片描述

5.5 多层@Builder方法嵌套使用

在@Builder方法内调用自定义组件或者其他@Builder方法,ArkUI提供$$作为按引用传递参数的范式。


class Tmp7 {paramA1: string = '';
}@Builder
function parentBuilder7($$: Tmp7) {Row() {Column() {Text(`parentBuilder7===${$$.paramA1}`).fontSize(20).fontWeight(FontWeight.Bold)HelloComponent7({ message: $$.paramA1 })childBuilder7({ paramA1: $$.paramA1 })}}
}@Component
struct HelloComponent7 {@Prop message: string = '';build() {Row() {Text(`HelloComponent7===${this.message}`).fontSize(20).fontWeight(FontWeight.Bold)}}
}@Builder
function childBuilder7($$: Tmp7) {Row() {Column() {Text(`childBuilder7===${$$.paramA1}`).fontSize(20).fontWeight(FontWeight.Bold)HelloChildComponent7({ message: $$.paramA1 })grandsonBuilder7({ paramA1: $$.paramA1 })}}
}@Component
struct HelloChildComponent7 {@Prop message: string = '';build() {Row() {Text(`HelloChildComponent7===${this.message}`).fontSize(20).fontWeight(FontWeight.Bold)}}
}@Builder
function grandsonBuilder7($$: Tmp7) {Row() {Column({ space: 10 }) {Text(`grandsonBuilder7===${$$.paramA1}`).fontSize(20).fontWeight(FontWeight.Bold)HelloGrandsonComponent7({ message: $$.paramA1 })}}
}@Component
struct HelloGrandsonComponent7 {@Prop message: string;build() {Row() {Text(`HelloGrandsonComponent7===${this.message}`).fontSize(20).fontWeight(FontWeight.Bold)}}
}@Entry
@Component
struct TestBuilder7 {@State label: string = 'Hello';build() {Column() {parentBuilder7({ paramA1: this.label })Button('Click me').onClick(() => {this.label = 'ArkUI';})}}
}

效果图

在这里插入图片描述

5.6 @Builder函数联合V2装饰器使用

使用全局@Builder和局部@Builder在@ComponentV2修饰的自定义组件中调用,修改相关变量触发UI刷新。

@ObservedV2
class Info8 {@Trace name: string = '';@Trace age: number = 0;
}@Builder
function overBuilder8(param: Info8) {Column() {Text(`全局@Builder name :${param.name}`).fontSize(30).fontWeight(FontWeight.Bold)Text(`全局@Builder age :${param.age}`).fontSize(30).fontWeight(FontWeight.Bold)}
}@ComponentV2
struct ChildPage8 {@Require @Param childInfo: Info8;build() {overBuilder8({name: this.childInfo.name, age: this.childInfo.age})}
}@Entry
@ComponentV2
struct TestBuilder8 {info1: Info = { name: "Tom", age: 25 };@Local info2: Info = { name: "Tom", age: 25 };@BuilderprivateBuilder() {Column() {Text(`局部@Builder name :${this.info1.name}`).fontSize(30).fontWeight(FontWeight.Bold)Text(`局部@Builder age :${this.info1.age}`).fontSize(30).fontWeight(FontWeight.Bold)}}build() {Column() {Text(`info1: ${this.info1.name}  ${this.info1.age}`) // Text1.fontSize(30).fontWeight(FontWeight.Bold)this.privateBuilder() // 调用局部@BuilderLine().width('100%').height(10).backgroundColor('#000000').margin(10)Text(`info2: ${this.info2.name}  ${this.info2.age}`) // Text2.fontSize(30).fontWeight(FontWeight.Bold)overBuilder8({ name: this.info2.name, age: this.info2.age}) // 调用全局@BuilderLine().width('100%').height(10).backgroundColor('#000000').margin(10)Text(`info1: ${this.info1.name}  ${this.info1.age}`) // Text1.fontSize(30).fontWeight(FontWeight.Bold)ChildPage8({ childInfo: this.info1}) // 调用自定义组件Line().width('100%').height(10).backgroundColor('#000000').margin(10)Text(`info2: ${this.info2.name}  ${this.info2.age}`) // Text2.fontSize(30).fontWeight(FontWeight.Bold)ChildPage8({ childInfo: this.info2}) // 调用自定义组件Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button("change info1&info2").onClick(() => {this.info1 = { name: "Cat", age: 18} // Text1不会刷新,原因是没有装饰器修饰监听不到值的改变。this.info2 = { name: "Cat", age: 18} // Text2会刷新,原因是有装饰器修饰,可以监听到值的改变。})}}
}

效果图

在这里插入图片描述

六、常见问题

6.1 @Builder存在两个或者两个以上参数

当参数存在两个或者两个以上的时候,就算通过对象字面量的形式传递,值的改变也不会引起UI刷新。

【反例1】

class GlobalTmp9 {str_value: string = 'Hello';
}@Builder function overBuilder9(param: GlobalTmp9, num: number) {Column() {Text(`str_value: ${param.str_value}`)Text(`num: ${num}`)}
}@Entry
@Component
struct TestBuilder9 {@State objParam: GlobalTmp9 = new GlobalTmp9();@State num: number = 0;build() {Column() {Text('通过调用@Builder渲染UI界面').fontSize(20)// 使用了两个参数,用法错误。overBuilder9({str_value: this.objParam.str_value}, this.num)Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button('点击改变参数值').onClick(() => {this.objParam.str_value = 'Hello World';this.num = 1;console.log(`执行了 onClick 事件, this.objParam.str_value =  ${this.objParam.str_value}, this.num = ${this.num} `)})}}
}

执行效果图

在这里插入图片描述

【反例2】

class GlobalTmp10 {str_value: string = 'Hello';
}
class SecondTmp10 {num_value: number = 0;
}
@Builder function overBuilder10(param: GlobalTmp10, num: SecondTmp10) {Column() {Text(`str_value: ${param.str_value}`)Text(`num: ${num.num_value}`)}
}@Entry
@Component
struct TestBuilder10 {@State strParam: GlobalTmp10 = new GlobalTmp10();@State numParam: SecondTmp10 = new SecondTmp10();build() {Column() {Text('通过调用@Builder渲染UI界面').fontSize(20)// 使用了两个参数,用法错误。overBuilder10({str_value: this.strParam.str_value}, {num_value: this.numParam.num_value})Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button('点击改变参数值').onClick(() => {this.strParam.str_value = 'Hello World';this.numParam.num_value = 1;console.log(`执行了 onClick 事件, this.strParam.str_value =  ${this.strParam.str_value}, this.numParam = ${this.numParam.num_value} `)})}}
}

执行效果图

在这里插入图片描述

@Builder只接受一个参数,当传入一个参数的时候,通过对象字面量的形式传递,值的改变会引起UI的刷新。

【正例】

class GlobalTmp11 {str_value: string = 'Hello';num_value: number = 0;
}@Builder
function overBuilder11(param: GlobalTmp11) {Column() {Text(`str_value: ${param.str_value}`)Text(`num: ${param.num_value}`)}
}@Entry
@Component
struct TestBuilder11 {@State objParam: GlobalTmp11 = new GlobalTmp11();build() {Column() {Text('通过调用@Builder渲染UI界面').fontSize(20)overBuilder11({ str_value: this.objParam.str_value, num_value: this.objParam.num_value })Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button('点击改变参数值').onClick(() => {this.objParam.str_value = 'Hello World';this.objParam.num_value = 11;})}}
}

效果图

在这里插入图片描述

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

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

相关文章

VISRAG论文介绍:一种直接的视觉RAG

今天给大家介绍一篇论文&#xff0c;VISRAG: VISION-BASED RETRIEVAL-AUGMENTED GENERATION ON MULTI-MODALITY DOCUMENTS [pdf]&#xff0c;一种直接的视觉RAG。 Source&#xff08;来源&#xff09;:ICLR2025 Summary: &#xff08;文献方向归纳 &#xff09;多模态RAG Mot…

在 .Net 8.0 中使用 AJAX 在 ASP.NET Core MVC 中上传文件

上传文件是现代 Web 应用程序中的常见要求。在 ASP.NET Core MVC 中&#xff0c;高效处理文件上传可以提高应用程序的可用性和性能。在本文中&#xff0c;我们将探讨如何使用 AJAX 在 ASP.NET Core MVC 应用程序中实现文件上传&#xff0c;通过允许文件上传而无需刷新整个页面&…

简单的spring boot tomcat版本升级

简单的spring boot tomcat版本升级 1. 需求 我们使用的springboot版本为2.3.8.RELEASE&#xff0c;对应的tomcat版本为9.0.41&#xff0c;公司tomcat对应版本发现攻击者可发送不完整的POST请求触发错误响应&#xff0c;从而可能导致获取其他用户先前请求的数据&#xff0c;造…

linux系统(ubuntu,uos等)连接鸿蒙next(mate60)设备

以前在linux上是用adb连接&#xff0c;现在升级 到了鸿蒙next&#xff0c;adb就不好用了。得用Hdc来了&#xff0c;在windows上安装了hisuit用的好好的&#xff0c;但是到了linux(ubuntu2204)下载安装了 下载中心 | 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生…

C++:位与运算符

& 一&#xff0c;位与运算符的运算规则 有0则0。 二&#xff0c;判断奇偶性 %&#xff1a;优先级高&#xff0c;效率低 &&#xff1a;优先级低&#xff0c;效率高 数与1的位与运算结果为1则为奇数&#xff0c;结果为0则为偶数 三&#xff0c;获取一个数二进制的后…

(已开源-AAAI25) RCTrans:雷达相机融合3D目标检测模型

在雷达相机融合三维目标检测中&#xff0c;雷达点云稀疏、噪声较大&#xff0c;在相机雷达融合过程中提出了很多挑战。为了解决这个问题&#xff0c;我们引入了一种新的基于query的检测方法 Radar-Camera Transformer (RCTrans)。具体来说&#xff1a; 首先设计了一个雷达稠密…

如何利用PHP爬虫按关键字搜索淘宝商品

在当今的电商时代&#xff0c;获取淘宝商品信息对于市场研究、价格监控和竞争分析等方面具有重要意义。手动搜索和整理大量商品信息不仅耗时耗力&#xff0c;而且容易出错。幸运的是&#xff0c;PHP爬虫技术为我们提供了一种高效、自动化的方式来按关键字搜索淘宝商品。本文将详…

【数据可视化-11】全国大学数据可视化分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

ceph集群配置

4台机器 高度可扩展&#xff0c;分布式的存储文件系统&#xff0c;旨在提供高性能&#xff0c;高可靠性和高可用的对象存储&#xff0c;块存储&#xff0c;文件系统的存储。 使用分布式的算法保证数据的高可用和一致性。 ceph的架构&#xff1a; 1、ceph minitor MON&…

winform中使用panuon开源UI库的问题

在 WinForms 中使用 Panuon UI 是一种提高应用程序用户界面美观和交互性的方式。Panuon UI 是一个用于 .NET 应用程序的现代化 UI 库&#xff0c;它提供了一些非常好看的控件&#xff0c;能够让 WinForms 应用程序看起来更现代。 But------------------------------------&…

【Uniapp-Vue3】swiper滑块视图容器的用法

我们使用swiper标签就可以实现轮播图的效果。 一、swiper组件的结构 整体的轮播图使用swiper标签&#xff0c;轮播的每一页使用swiper-item标签。 <template><swiper class"swiper"><swiper-item><view class"swiper-item">111…

Which CAM is Better for Extracting Geographic Objects? A Perspective From参考文献

参考文献列表 [1] E. Shelhamer, J. Long, and T. Darrell, “Fully convolutional networks for semantic segmentation,” in Proc. Comput. Vis. Pattern Recognit., Jun. 2015, pp. 3431–3440. 中文翻译&#xff1a;[1] 谢尔哈默, E., 龙, J., & 达雷尔, T. (2015).…

【C++项目实战】类和对象入门实践:日期类实现万字详解

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C项目实战》 期待您的关注 ​ 目录 引言 介绍 一、类的设计 二、成员函数的实现 &#x1f343;构造函数、析构函数、拷贝构造…

基于32单片机的智能语音家居

一、主要功能介绍 以STM32F103C8T6单片机为控制核心&#xff0c;设计一款智能远程家电控制系统&#xff0c;该系统能实现如下功能&#xff1a; 1、可通过语音命令控制照明灯、空调、加热器、窗户及窗帘的开关&#xff1b; 2、可通过手机显示和控制照明灯、空调、窗户及窗帘的开…

hot100_54. 螺旋矩阵

hot100_54. 螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a; 输入&am…

HTML5实现好看的博客网站、通用大作业网页模板源码

HTML5实现好看的博客网站、通用大作业网页模板源码 前言一、设计来源1.1 主界面1.2 列表界面1.3 文章界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的博客网站、通用大作业网页模板源码&#xff0c;博客网站源码&#xff0c;HTML模板源码&#xff0…

移动硬盘无法访问:全面解析、恢复方案与预防策略

描述移动硬盘无法访问现象 在日常的数据存储和传输过程中&#xff0c;移动硬盘无疑扮演着举足轻重的角色。然而&#xff0c;当移动硬盘突然无法访问时&#xff0c;这无疑给用户带来了巨大的困扰。想象一下&#xff0c;你急需从移动硬盘中调取一份重要文件&#xff0c;但系统却…

1-markdown转网页样式页面 --[制作网页模板] 【测试代码下载】

markdown转网页 将Markdown转换为带有样式的网页页面通常涉及以下几个步骤&#xff1a;首先&#xff0c;需要使用Markdown解析器将Markdown文本转换为HTML&#xff1b;其次&#xff0c;应用CSS样式来美化HTML内容。此外&#xff0c;还可以加入JavaScript以增加交互性。下面我将…

基于Centos 7系统的安全加固方案

创作不易&#xff0c;麻烦点个免费的赞和关注吧&#xff01; 声明&#xff01; 免责声明&#xff1a;本教程作者及相关参与人员对于任何直接或间接使用本教程内容而导致的任何形式的损失或损害&#xff0c;包括但不限于数据丢失、系统损坏、个人隐私泄露或经济损失等&#xf…

Angular由一个bug说起之十三:Cross Origin

跨域 想要了解跨域&#xff0c;首要要了解源 什么是源&#xff0c;源等于协议加域名加端口号 只有这三个都相同&#xff0c;才是同源&#xff0c;反之则是非同源。 比如下面这四个里&#xff0c;只有第4个是同源 而浏览器给服务器发送请求时&#xff0c;他们的源一样&#xff0…