HarmonyOS 状态管理

news2024/10/7 20:32:58

在声明式 UI 框架中,数据的改变触发 UI 的重新渲染。在 ArkUI 中不是所有数据的变化都会触发 UI 重新渲染,只有 状态变量 才会引起 UI 重新渲染。

状态变量

状态变量: 指被状态装饰器装饰的变量,只有这种变量的改变才会引起 UI 的重新渲染。

常规变量: 指没有被状态装饰器装饰的变量,不会引起 UI 的重新渲染。

按影响范围分为:

  • 组件级别的状态: @State, @Prop, @Link, @Provide/@Consume, @Observed, @ObjectLink
  • 应用级别的状态:@StorageLink/@LocalStorageLink, @StorageProp/@LocalStorageProp

按传递方向分为:

  • 只读的单向传递
  • 可变更的双向传递

q.png

@State 组件内状态

@State 装饰的状态变量,是组件内的状态,是私有的,只能从组件内部访问,不与父组件中任何类型的状态变量同步。

允许装饰的变量类型:Object、class、string、number、boolean、enum,Date, 以及这些类型的数组。API11及以上支持Map、Set, undefined,null 和 联合类型

@State 装饰原始类型

@Entry
@Component
struct StatePage {
  @State text: string = 'HarmonyOS'
  @State count: number = 0

  build() {
    Column({ space: 10 }) {
      Text('string: ' + this.text).fontSize(17)
      Text('number: ' + this.count)
      Button('text = "Android"').onClick((event: ClickEvent) => {
        this.text = 'Android'
      })
      Button('count++').onClick((event: ClickEvent) => {
        this.count++
      })
    }
    .width('100%')
    .height('100%')
  }
}

点击 Button 修改了 text,count 变量的值,会触发 UI 重新渲染,显示最新的值。

@State 装饰 class

export class User {
  name: string
  car?: Car

  constructor(name: string, car?: Car) {
    this.name = name;
    this.car = car;
  }
}

export class Car {
  brand: string
  engine?: Engine

  constructor(brand: string, engine?: Engine) {
    this.brand = brand;
    this.engine = engine;
  }
}

export class Engine {
  type?: string

  constructor(type: string) {
    this.type = type;
  }
}
@Entry
@Component
struct StateClassPage {
  @State user: User = new User('Jack')
  build() {
    Column({space: 10}) {
      Text('Class: ' + `name=${this.user.name}, car=${this.user.car?.brand}`).fontSize(17)
      Column({ space: 10 }) {
        Button(`user = new User('Mike')`).onClick((event: ClickEvent) => {
          // 有效刷新
          this.user = new User('Mike')
        })
        Button(`user.name = 'Pony New'`).onClick((event: ClickEvent) => {
          // 有效刷新
          this.user.name = 'Pony New'
        })
        Button(`user.car = new Car('Benz')`).onClick((event: ClickEvent) => {
          // 有效刷新,@State 可以观察到一级属性 car 的赋值
          this.user.car = new Car('Benz')
        })
        Button(`this.user.car.brand = 'BMW'`).onClick((event: ClickEvent) => {
          // 无效刷新, user.car.brand, user.car.engine 为二级属性, @State 观察不到, 需要使用 @Observed 和 @ObjectLink
          if (this.user.car) {
            this.user.car.brand = 'BMW'
          }
        })
      }
    }.width('100%')
  }
}

对于 @State 装饰的 Class 状态变量, ArkUI 只能观察到状态变量的一级属性的变化,从而引起 UI 重新渲染。如上例中 user.name 和 user.car 是 User 的一级属性,user.car.brand 是 User 的二级属性, 所以点击Button执行 this.user.car.brand = 'BMW' UI 没有刷新,这种情况,需要使用 @Observed/@ObjectLink

@State 装饰数组

@Entry
@Component
struct StateArrayPage {
  @State stringArray: string[] = ['Java', 'Kotlin']
  @State userArray: User[] = [new User('Jack'), new User('Make')]

  build() {
    Column({ space: 10 }) {
      ForEach(this.stringArray, (item: string) => {
        Text(item)
      })
      Row({ space: 6 }) {
        Button('add').onClick((event: ClickEvent) => {
          this.stringArray.push('Typescript')
        })
        Button('remove').onClick((event: ClickEvent) => {
          if (this.stringArray.length > 0) {
            this.stringArray.splice(0, 1)
          }
        })
        Button('update').onClick((event: ClickEvent) => {
          if (this.stringArray.length > 0) {
            this.stringArray[0] = 'Javascript by updated'
          }
        })
        Button('new Array()').onClick((event: ClickEvent) => {
          this.stringArray = ['New Array1', 'New Array2']
        })
      }

      Divider().height(20).color(Color.Gray)

      ForEach(this.userArray, (item: User) => {
        Text(`name=${item.name},car=${item.car}`)
      })
      Column({ space: 10 }) {
        Button('add').onClick((event: ClickEvent) => {
          this.userArray.push(new User('Jane'))
        })
        Button('remove').onClick((event: ClickEvent) => {
          if (this.stringArray.length > 0) {
            this.userArray.splice(0, 1)
          }
        })
        Button('update userArray[0]=new User("Lace")').onClick((event: ClickEvent) => {
          if (this.stringArray.length > 0) {
            // class 数组, 可以观察到数组中元素 重新赋值
            this.userArray[0] = new User('Lace')
          }
        })
        Button('userArray[0].name="Shane"').onClick((event: ClickEvent) => {
          // 无效刷新, 对于 class数组, 观察不到数组中 元素的属性 赋值
          this.userArray[0].name = 'Shane'
        })
      }
    }
    .width('100%')
  }
}

对于数组,ArkUI 可以观察到 数组新增,删除,重新创建数组, 数组项重新赋值,从而引起 UI 重新渲染,无法观察到 数组中某个元素的 属性的变化

@Prop 父 —> 子单向同步

@Prop 是单向同步的:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上。

@Entry
@Component
struct PropPage {
  @State text: string = 'ArkUI'
  @State user: User = new User('Jane', new Car('Benz E'))

  build() {
    Column({ space: 10 }) {
      Text(this.text).onClick(() => {
        this.text = 'Flutter '
      })
      Text(`name:${this.user.name},car=${this.user.car?.brand}`)
        .onClick(()=> {
          this.user = new User('parent User')
        })
      Divider().height(20)
      PropChild({ title: this.text, user: this.user })
    }.width('100%')
  }
}

@Component
struct PropChild {
  /**
   * 修改父组件的状态变量可以同步刷新子组件, 而修改子组件的状态变量不会同步刷新父组件
   */
  @Prop title: string = 'default'
  @Prop user: User

  build() {
    Column({ space: 10 }) {
      Text(this.title).onClick(() => {
        this.title = 'JetpackCompose'
      })
      Text(`name:${this.user.name},car=${this.user.car?.brand}`)
      Button('user=new User("Shine")').onClick((event: ClickEvent) => {
        this.user = new User('Shine')
      })
      Button('user.car = new Car("Audi A6")').onClick((event: ClickEvent) => {
        this.user.car = new Car('Audi A6')
      })
      Button('user.car.brand="BWM 530"').onClick((event: ClickEvent) => {
        if (this.user.car) {
          this.user.car.brand = 'BWM 530'
        }
      })
    }
  }
}

@Prop 装饰的状态变量, ArkUI 同样观察不到 二级属性的变化,并且子组件状态变量的变化不会引起父组件 UI 的刷新, 但父组件状态变量的变化可以引起子组件的刷新。

@Link 父子双向同步

子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定.

@Link装饰器不能在@Entry装饰的自定义组件中使用。

@Link 装饰原始类型

@Entry
@Component
struct LinkBasicPage {
  @State text: string = 'ArkUI'
  build() {
    Column({ space: 10 }) {
      Text('父组件:' + this.text).onClick(() => {
        this.text = 'Flutter '
      })
      LinkBasicChild({ title: $text })
    }.width('100%')
  }
}

@Component
struct LinkBasicChild {
  // @Link装饰的状态变量禁止初始化
  // @Link title: string = ''
  @Link title: string
  build() {
    Column({ space: 10 }) {
      Text('子组件:' + this.title).onClick(() => {
        this.title = 'JetpackCompose'
      })
    }
  }
}

父子组件的状态变量的变化,可以相互引起 UI 刷新

@Link 装饰 class

@Entry
@Component
struct LinkClassPage {
  @State user: User = new User('Jane', new Car('Benz E'))
  build() {
    Column({ space: 10 }) {
      Text(`父组件 name=${this.user.name},car=${this.user.car?.brand}`)
      Button('user=new User("Mike")').onClick((event: ClickEvent) => {
        this.user = new User('Mike-P')
      })
      Divider()
      LinkClassChild({ user: $user })
    }.width('100%')
  }
}

@Component
struct LinkClassChild {
  // 禁止本地初始化
  @Link user: User

  build() {
    Column({ space: 10 }) {
      Text(`子组件 name=${this.user.name},car=${this.user.car?.brand}`)
      Button('user=new User("Shine")').onClick((event: ClickEvent) => {
        this.user = new User('Shine')
      })
      Button('user.car = new Car("Audi A6")').onClick((event: ClickEvent) => {
        this.user.car = new Car('Audi A6')
      })
      Button('user.car.brand="BWM 530"').onClick((event: ClickEvent) => {
        if (this.user.car) {
          this.user.car.brand = 'BWM 530'
        }
      })
    }
  }
}

@Link 装饰的状态变量, ArkUI 同样观察不到 二级属性的变化。一级属性可以引起父子组件UI 的刷新。

@Link 装饰数组

@Entry
@Component
struct LinkArrayPage {
  @State list: string[] = ['Android', 'iOS', 'Harmony']
  build() {
    Column({ space: 10 }) {
      ForEach(this.list, (item: string) => {
        Text(item)
      })
      Button('new Array').onClick((event: ClickEvent) => {
        this.list = new Array<string>('Benz', 'BMW', 'Audi')
      })
      Button('Add').onClick((event: ClickEvent) => {
        this.list.push('parent add')
      })
      Button('remove').onClick((event: ClickEvent) => {
        if (this.list.length > 0) {
          this.list.splice(0, 1)
        }
      })
      Button('update').onClick((event: ClickEvent) => {
        if (this.list.length > 0) {
          this.list[0] = 'parent update'
        }
      })
      Divider()
      LinkArrayChild({ childList: $list })
    }.width('100%')
  }
}

@Component
struct LinkArrayChild {
  @Link childList: string[]
  build() {
    Column({ space: 10 }) {
      ForEach(this.childList, (item: string) => {
        Text(item)
      })
      Button('new Array').onClick((event: ClickEvent) => {
        this.childList = new Array<string>('Kotlin', 'Swift', 'ArkTS')
      })
      Button('Add').onClick((event: ClickEvent) => {
        this.childList.push('child Add')
      })
      Button('remove').onClick((event: ClickEvent) => {
        if (this.childList.length > 0) {
          this.childList.splice(0, 1)
        }
      })
      Button('update').onClick((event: ClickEvent) => {
        if (this.childList.length > 0) {
          this.childList[0] = 'child update'
        }
      })
    }
  }
}

@Provide/@Consume 父与后代组件双向同步

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。

@Provide/@Consume 装饰原始类型

@Entry
@Component
struct ProvideConsumeBasicPage {
  @Provide count: number = 1

  build() {
    Column({ space: 10 }) {
      Text(this.count.toString()).onClick(() => {
        this.count++
      })
      ProvideChild()
    }
    .width('100%')
  }
}

@Component
struct ProvideChild {
  @Consume count: number

  build() {
    Column({ space: 10 }) {
      Text(this.count.toString()).onClick(() => {
        this.count += 2
      })
      ProvideChildSecond()
    }
    .backgroundColor(Color.Brown)
    .padding(30)
  }
}

@Component
struct ProvideChildSecond {
  @Consume count: number

  build() {
    Column() {
      Text(this.count.toString()).onClick(() => {
        this.count += 3
      })
    }
    .backgroundColor(Color.Pink)
    .padding(30)
  }
}

@Provide/@Consume 装饰 class

@Entry
@Component
struct ProvideConsumeClassPage {
  @Provide user: User = new User('Apple')
  build() {
    Column({ space: 10 }) {
      Text('父组件:' + this.user.name)
      Button('user.name="parent"').onClick((event: ClickEvent) => {
        this.user.name = 'parent'
      })
      Divider()
      ProvideClassChild()
    }.width('100%')
  }
}

@Component
struct ProvideClassChild {
  @Consume user: User
  build() {
    Column({ space: 10 }) {
      Text('孩子组件:' + this.user.name)
      Divider()
      ProvideClassChildSecond()
    }
  }
}

@Component
struct ProvideClassChildSecond {
  @Consume user: User
  build() {
    Column({ space: 10 }) {
      Text('孙子组件:' + this.user.name)
      Divider()
      ProvideClassChildThird()
    }
  }
}

@Component
struct ProvideClassChildThird {
  @Consume user: User
  build() {
    Column({ space: 10 }) {
      Text('曾孙子:' + this.user.name)
      Button('user=new User("曾孙子")').onClick((event: ClickEvent) => {
        this.user = new User('曾孙子')
      })
      Button('user.name="曾孙name:sx"').onClick((event: ClickEvent) => {
        this.user.name="曾孙name:sx"
      })
      Button('user.car.brand = "曾孙.name.car: Benz S"').onClick((event: ClickEvent) => {
        if (this.user.car) {
          this.user.car.brand = '曾孙.name.car: Benz S'
        }
      })
    }
  }
}

@Oberved/@ObjectLink 嵌套类对象属性变化

上述 @State, @Prop,@Link 和 @Provide/@Consume 装饰器只能观察 class 一级属性赋值,无法观察二级属性变化,但在实际开发过程中,class 的属性类型仍是 class 类型是很常用见的,因此就需要使用 @Observed/@ObjectLink 来实现了。

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

  • 被@Observed装饰的类,可以被观察到属性的变化;
  • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
  • 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
  • @ObjectLink 装饰的变量必须为被@Observed装饰的class实例
  • @ObjectLink 装饰的变量不允许重新赋值。

@ObjectLink 装饰 class

@Entry
@Component
struct ObjectLinkBasicPage {
  @State user: User = new User('Jack', new Car('BMW 3 serial'))
  build() {
    Column({ space: 10 }) {
      Button(`user.car.brand = 'BMW'`).onClick((event: ClickEvent) => {
        if (this.user.car) {
          this.user.car.brand = 'Benz E class'
        }
      })
      Divider()
      CarItem({ car: this.user.car })
    }.width('100%')
  }
}

@Component
struct CarItem {
  // Car 需要被 @Observed 装饰
  @ObjectLink car: Car

  build() {
    Column() {
      Text('car: ' + this.car.brand)
      Button('car=new Car("audi")').onClick((event: ClickEvent) => {
        // 报错,@ObjectLink装饰的状态变量不允许被赋值, 可以对它的属性赋值
        // this.car = new Car('audi')
        this.car.brand = 'audi'
      })
    }
    .width('90%')
    .padding(20)
    .backgroundColor(Color.Pink)
  }
}

@ObjectLink 装饰数组中数组项

@Entry
@Component
struct ObjectLinkBasicPage {
  @State userArray: User[] = [
    new User('Jack', new Car('BMW 3 serial')),
    new User('Mike', new Car('Audi A4L'))
  ]

  build() {
    Column({ space: 10 }) {
      Button(`userArray[0].car.brand = 'Benz S class'`).onClick((event: ClickEvent) => {
        if (this.userArray.length > 0) {
          let user: User = this.userArray[0]
          if (user.car) {
            user.car.brand = 'Benz S class'
          }
        }
      })
      ForEach(this.userArray, (item: User) => {
        UserItem({ user: item })
      })
    }.width('100%')
  }
}

@Component
struct UserItem {
	// User 需要被 @Observed 装饰
  @ObjectLink user: User

  build() {
    CarItem({ car: this.user.car })
  }
}

@Component
struct CarItem {
  // Car 需要被 @Observed 装饰
  @ObjectLink car: Car

  build() {
    Column() {
      Text('car: ' + this.car.brand)
    }
    .width('90%')
    .padding(20)
    .backgroundColor(Color.Pink)
  }
}

ViewModel 存储数据

@Entry
@Component
struct ViewModelPage {
  @State viewModel: UserViewModel = new UserViewModel([
    new User('jack', new Car('保时捷')),
    new User('mack', new Car('奔驰'))
  ])

  build() {
    Scroll() {
      Column() {
        Flex({ wrap: FlexWrap.Wrap }) {
          Button('new Array')
            .margin(6)
            .onClick((event: ClickEvent) => {
              this.viewModel.userList = [new User('new kotlin')]
            })

          Button('add')
            .margin(6)
            .onClick((event: ClickEvent) => {
              this.viewModel.userList.push(new User('kotlin'))
            })

          Button('remove')
            .margin(6)
            .onClick((event: ClickEvent) => {
              if (this.viewModel.userList.length > 0) {
                this.viewModel.userList.splice(0, 1)
              }
            })

          Button('viewModel.userList[0]=new User("peter")')
            .margin(6)
            .onClick((event: ClickEvent) => {
              if (this.viewModel.userList.length > 0) {
                this.viewModel.userList[0] = new User('peter', new Car('马自达'))
              }
            })

          Button('viewModel.userList[0].name="张三"')
            .margin(6)
            .onClick((event: ClickEvent) => {
              if (this.viewModel.userList.length > 0) {
                this.viewModel.userList[0].name = '张三'
              }
            })

          Button('viewModel.userList[0].car.brand="XIAOMI SU7 MAX"')
            .margin(6)
            .onClick((event: ClickEvent) => {
              if (this.viewModel.userList.length > 0) {
                let car = this.viewModel.userList[0].car
                if (car) {
                  car.brand = 'XIAOMI SU7 MAX'
                }
              }
            })
        }
        ChildUser({ userList: this.viewModel.userList })
      }
    }
  }
}

@Component
struct ChildUser {
  // ObservableArray 需要被 @Observed 装饰
  @ObjectLink userList: ObservableArray<User>

  build() {
    Column() {
      ForEach(this.userList, (user: User) => {
        UserItem({ user: user })
        Divider()
      })
    }.padding(20)
  }
}

@Component
struct UserItem {
  // User 需要被 @Observed 装饰
  @ObjectLink user: User

  build() {
    Column() {
      Text('user.name: ' + this.user.name)
      CarItem({ car: this.user.car })
    }
  }
}

@Component
struct CarItem {
  // Car 需要被 @Observed 装饰
  @ObjectLink car: Car | undefined

  build() {
    Text('user.car: ' + this.car?.brand)
  }
}


@Observed
export class ObservableArray<T> extends Array<T> {
  constructor(args: T[]) {
    if (args instanceof Array) {
      super(...args);
    } else {
      super(args)
    }
  }
}

@ObservedV2装饰器和@Trace装饰器:类属性变化观测

从 API12 开始,更推荐使用@ObservedV2装饰器和@Trace装饰器装饰类以及类中的属性,来管理状态。

@ObservedV2
class Father {
  @Trace name: string = "Tom";
}
class Son extends Father {
}
@Entry
@Component
struct Index {
  son: Son = new Son();

  build() {
    Column() {
      // 当点击改变name时,Text组件会刷新
      Text(`${this.son.name}`)
        .onClick(() => {
          this.son.name = "Jack";
      })
    }
  }
}

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

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

相关文章

(2022级)成都工业学院数据库原理及应用实验七: 数据库安全

写在前面 1、基于2022级软件工程/计算机科学与技术实验指导书 2、成品仅提供参考 3、如果成品不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 Navicat Premium 16 Mysql 8.0.36 实验要求 1、创建数据库hospital,在hospital数据库中创建科室表De…

第一个STM32F767IGT6核心板

一. 制作原因 起先是因为参加计算机设计大赛准备的板子&#xff0c;其作用是连接OV5640摄像头来识别车牌号&#xff0c;主要外设有摄像头&#xff0c;SDRAM&#xff0c;网口等。 二. 原理图和PCB 原理图 PCB 三. 测试 1. 测试SDRAM功能 按下按键我们可以在串口中看到内存…

LTspice/Simplis仿真代码使用

LTspice/Simplis仿真代码使用 HI uu们 HI uu们,关注我的uu经常看到我上面贴了很多仿真代码,但是不知道怎么用. 今天来介绍下仿真代码怎么用, 比如说,我们用OP07做了一个跟随器,如图1所示. 图1:OP07跟随器 他的仿真代码非常简单,如下所示 XU1 N002 vout N001 N003 vout LT…

【Linux】详解进程通信中信号量的本质同步和互斥的概念临界资源和临界区的概念

一、同步和互斥的概念 1.1、同步 访问资源在安全的前提下&#xff0c;具有一定的顺序性&#xff0c;就叫做同步。在多道程序系统中&#xff0c;由于资源有限&#xff0c;进程或线程之间可能产生冲突。同步机制就是为了解决这些冲突&#xff0c;保证进程或线程之间能够按照既定…

都以为他是自杀20年后遗书曝光才明白张国荣的离世不简单

在时光的长河中&#xff0c;有些瞬间如同流星划过天际&#xff0c;短暂却又璀璨夺目。二十年前的那个春天&#xff0c;一个灵魂从这个喧嚣世界悄然离去&#xff0c;留下无尽的叹息与疑问。他就是张国荣——一位被誉为“风华绝代”的巨星。许多人曾认定他的离开是一场悲剧性的自…

计算机网络 -- 多人聊天室

一 程序介绍和核心功能 这是基于 UDP 协议实现的一个网络程序&#xff0c;主要功能是 构建一个多人聊天室&#xff0c;当某个用户发送消息时&#xff0c;其他用户可以立即收到&#xff0c;形成一个群聊。 这个程序由一台服务器和n个客户端组成&#xff0c;服务器扮演了一个接受…

element-ui合计逻辑踩坑

element-ui合计逻辑踩坑 1.快速实现一个合计 ​ Element UI所提供的el-table中提供了方便快捷的合计逻辑实现&#xff1a; ​ https://element.eleme.cn/#/zh-CN/component/table ​ 此实现方法在官方文档中介绍详细&#xff0c;此处不多赘述。 ​ 这里需要注意&#xff0c…

Don‘t fly solo! 量化之路,AI伴飞

在投资界&#xff0c;巴菲特与查理.芒格的神仙友谊&#xff0c;是他们财富神话之外的另一段传奇。巴菲特曾这样评价芒格&#xff1a;他用思想的力量拓展了我的视野&#xff0c;让我以火箭的速度&#xff0c;从猩猩进化到人类。 人生何幸能得到一知己。如果没有这样的机缘&…

每日学习笔记:C++ STL算法之容器元素变序

目录 反转元素次序 reverse(beg, end) reverse_copy(srcBeg, srcEnd, destEnd) 旋转元素 旋转&#xff1a;rotate(beg, newBeg, end) 复制同时旋转&#xff1a;rotate_copy(srcBeg, srcNewBeg, srcEnd, destBeg) 对元素做排列组合情况列举与切换 next_permutation(beg, …

国产化里程碑:明道云HAP私有部署版获信创评估证书,荣登会员单位

近期&#xff0c;明道云HAP私有部署版荣获信创产品评估证书&#xff0c;这一成就不仅标志着我们在信创领域的深入布局和持续努力获得了行业的广泛认可&#xff0c;也是对我们积极拥抱和推动国产化技术发展的肯定。更值得一提的是&#xff0c;我们还被授予“成员单位”的称号&am…

基于通达信---做T专用算法

什么是做T? 股票做T是股票市场中常见的一种投资策略,也就是股票进行T+0操作,通过当天买进的股票,在当天卖出,是股市中常见的一种超短线的操作。其中T就是指交易日,利用交易日中的股票涨跌来赚取差价。股票做T常见的类型就是正T和倒T。 1、正T 股票做正t就是指先买后卖,…

Rokid AR Lite空间计算套装发布,中国空间计算踏上差异化领先之路

动动手指、动动眼睛就可以“操控一切”&#xff0c;这种颇具科幻感、未来感的交互方式&#xff0c;令许多人感叹“未来已来”。而这令人震撼的变革背后&#xff0c;正是空间计算技术的迅猛崛起与广泛应用&#xff0c;使得这种曾经只存在于想象中的交互方式&#xff0c;如今正逐…

快速访问github

修改本地hosts文件 GitHub访问慢的原因在于域名解析&#xff0c;通过修改本地的hosts文件&#xff0c;将远程DNS解析改为本地DNS解析。 fang 步骤1&#xff1a;打开hosts文件&#xff08;没有就创建&#xff09; host所在位置&#xff1a; C:\Windows\System32\drivers\etc…

linux jenkins 2.89.1 安装部署 持续构建svn下maven项目并部署到tomcat

从这边博文可以学习到&#xff1a; jenkins的安装修改主目录初始化新建任务&#xff0c;构建第一个maven项目将构建完成的项目部署到tomcat Jenkins的安装相当简单&#xff0c;只需要从官网下载war包&#xff0c;放入tomcat&#xff0c;运行tomcat就可以访问Jenkins了 准备工作…

PyCharm,终端conda环境无法切换的问题(二个解决方案)

问题 PyCharm终端&#xff0c;环境切换无效&#xff0c;默认始终为base 解决一 Settings->Tools->Terminal->ShellPath&#xff0c;将powershell修改为cmd.exe 解决二 conda config --show在输出中找到 auto_activate_base 的行&#xff0c;发现被设置为 true&#x…

数据结构-双链表(图解)

目录 双链表&#xff08;Double-Linked List&#xff09;的概念与基本特性 一、双链表的基本组成 二、双链表的主要特性 三、双链表的操作 代码展示 malloc开辟函数 解析 初始化 解析 头插 解析 尾插 解析 头删 解析 尾删 解析 pos之后插入 解析 pos删除 …

抖音小店无货源怎么做?教你新店快速起店新攻略,你还在等什么?

大家好&#xff0c;我是电商花花。 从我关注抖音小店这个风口到现在已经有很长时间了&#xff0c;从了解到实操到复盘&#xff0c;陆陆续续将多家单店店铺月营业额达到数百万。 目前团队运营着80多家店铺&#xff0c;人均管理3-5个店铺&#xff0c;大部分店铺月营业额都在5W-…

【C++】飞机大战项目记录

源代码与图片参考自《你好编程》的飞机大战项目&#xff0c;这里不进行展示。 本项目是仅供学习使用的项目 飞机大战项目记录 飞机大战设计报告1 项目框架分析1.1 敌机设计&#xff1a;1.2 玩家飞机控制&#xff1a;1.3 子弹发射&#xff1a;1.4 游戏界面与互动&#xff1a;1.5…

文本美学:text-image打造视觉吸引力

当我最近浏览 GitHub 时&#xff0c;偶然发现了一个项目&#xff0c;它能够将文字、图片和视频转化为文本&#xff0c;我觉得非常有趣。于是我就花了一些时间了解了一下&#xff0c;发现它的使用也非常简单方便。今天我打算和家人们分享这个发现。 项目介绍 话不多说&#xf…

OpenHarmony 上传和下载(API 10)教程~

介绍 本示例使用ohos.request接口创建上传和下载任务&#xff0c;实现上传、下载功能&#xff0c;hfs作为服务器&#xff0c;实现了文件的上传和下载和任务的查询功能。 效果预览 使用说明 1.本示例功能需要先配置服务器环境后使用&#xff0c;具体配置见上传下载服务配置。…