鸿蒙NEXT开发-组件事件监听和状态管理(基于最新api12稳定版)

news2024/11/22 16:11:57

注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下

如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识

专栏地址: https://blog.csdn.net/qq_56760790/category_12794123.html

目录

1. 组件事件

1.1 登录小案例

2. 组件状态管理

2.1 @State装饰器:组件内状态

2.1.1 基本介绍

2.1.2 简单代码示例-字符串类型

2.1.3 简单代码示例-number类型

2.1.4 简单代码示例-对象类型

2.1.5 简单代码示例-嵌套对象-不能触发视图更新

2.2 @Prop装饰器:父子单向同步

2.2.1 基本介绍

2.2.2 简单代码示例

2.3 @Link装饰器:父子双向同步

2.3.1 基本介绍

2.3.2 简单代码示例

2.4 @Provide和@Consume装饰器:与后代组件双向同步

2.4.1 基本介绍

2.4.2 简单代码示例

2.5 @Observed和@ObjectLink装饰器:嵌套类对象属性变化

2.5.1 基本介绍

2.5.2 简单代码示例

3. 排行榜小案例

3.1 代码结构

3.2 Index.ets

3.3 FruitModel.ets

3.4 TitleComponent.ets

3.5 TableHeaderComponent.ets

3.6 ItemComponent.ets

4. 学习地址


1. 组件事件

监听原生组件的事件和设置属性的方式是一样的都是链式调用,值得注意的是,我们注册事件必须使用箭头函数的写法,Next版本禁止使用匿名函数的形式来给组件注册事件

  • 匿名函数 function () {}

  • 尝试给一个TextInput和一个按钮注册一个值改变事件和点击事件

@Entry
  @Component
  struct Index {

    build() {
      Row() {
        Column({ space: 15 }) {
          Row() {
            TextInput({ placeholder: '请输入用户名' })
              .backgroundColor('#f4f5f6')
              .width('100%').onChange((value) => {
                console.log(value)
              })
          }.padding({
            left: 20,
            right: 20
          })

          Row() {
            Button("登录")
              .width('100%')
              .onClick(() => {
                AlertDialog.show({
                  message: '登录成功'
                })
              })

          }.padding({
            left: 20,
            right: 20
          })

        }
        .width('100%')
      }
      .height('100%')
    }
  }

  • promptAction弹出需要引入一个包才可以使用的,功能更多一些
  • AlertDialog 不需要引入包使用的,功能单一

请注意:在注册事件中的逻辑必须使用箭头函数 () => {}

  1. 因为function中this指向为undefind
  2. 箭头函数中的this指向当前struct实例,可以方便的调用方法和获取属性

1.1 登录小案例

import { promptAction } from '@kit.ArkUI'

@Entry
  @Component
  struct Index {
    /**
   * 手机号
   */
    @State phone:string=''

    /**
   * 验证码
   */
    @State code:string=''

    /**
    * 获取验证码
    */
    getCode(){
      // 判断手机号是否存在
      if(this.phone===''){
        promptAction.showToast({
          message:'手机号不能为空'
        })
        return
      }
      promptAction.showToast({
        message:'获取短信验证码成功,当前验证码是1234'
      })
    }

    /**
   * 登录
   */
    login(){
      if(this.phone!='' && this.code==='1234'){
        promptAction.showToast({message:'登录成功'})
        return
      }
      promptAction.showToast({message:'登录失败'})
      // 恢复手机号跟验证码初始化的值
      this.phone=''
      this.code=''
    }

    build() {
      Column() {
        // 华为账号登录
        Column({space:20}){
          TextInput({placeholder:'请输入手机号',text:this.phone})
            .width(300)
            .borderRadius(2)
            .onChange((value)=>{
              this.phone=value
            })
          TextInput({placeholder:'请输入验证码',text:this.code})
            .type(InputType.Password)
            .width(300)
            .borderRadius(2)
            .onChange((value)=>{
              this.code=value
            })

          Text('短信验证码登录').fontColor(Color.Blue).align(Alignment.Start).width('80%')
            .margin({bottom:10})
            .onClick(()=>{
              this.getCode()
            })

        }

        Button('登录')
          .width(300)
          .type(ButtonType.Normal)
          .borderRadius(10)
          .backgroundColor(Color.Red)
          .onClick(()=>{
            this.login()
          })
      }.justifyContent(FlexAlign.Center).width('100%').height('100%')
    }
  }

2. 组件状态管理

在声明式UI编程框架中,UI是程序状态的运行结果,用户构建了一个UI模型,其中应用的运行时的状态是参数。当参数改变时,UI作为返回结果,也将进行对应的改变。这些运行时的状态变化所带来的UI的重新渲染,在ArkUI中统称为状态管理机制。

2.1 @State装饰器:组件内状态

2.1.1 基本介绍

@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变。

需要注意的是,State修饰的类型

Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型以及数组中的对象属性无法触发视图更新

类型必须被指定。

不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。

2.1.2 简单代码示例-字符串类型

@Entry
@Component
struct Index {
   @State message:string='hello world'
  build() {
    Column(){
      Text(this.message).width(100).height(50).onClick(()=>{
        this.message='hello state'
      })

    }.width('100%').height('100%')
  }
}

2.1.3 简单代码示例-number类型

@Entry
@Component
struct Index {
   @State name:string='东林'
   @State age:number=18
  build() {
    Column(){
      Text(`${this.name}:${this.age}`)
        .width(100)
        .height(50)
        .onClick(()=>{
        this.age++
      })

    }.width('100%').height('100%')
  }
}

2.1.4 简单代码示例-对象类型

class People{
  name:string
  age:number

  constructor(name:string,age:number) {
    this.name=name
    this.age=age
  }
}

@Entry
  @Component
  struct Index {
    @State p:People=new People('东林',18)
    build() {
      Column(){
        Text(`${this.p.name}:${this.p.age}`)
          .width(100)
          .height(50)
          .onClick(()=>{
            this.p.age++
          })

      }.width('100%').height('100%')
    }
  }

2.1.5 简单代码示例-嵌套对象-不能触发视图更新

class People {
  name: string
  age: number
  model:Model

  constructor(name: string, age: number,model:Model) {
    this.name = name
    this.age = age
    this.model=model
  }
}

class Model{
  like:string=''
  constructor(like:string) {
    this.like=like
  }
}

@Entry
  @Component
  struct Index {
    @State p: People = new People('东林', 18, new Model('篮球'))

    build() {
      Column() {
        Text(`${this.p.model.like}`)
          .width(100)
          .height(50)
          .onClick(() => {
            this.p.model.like = '足球'
          })

      }.width('100%').height('100%')
    }
  }

2.2 @Prop装饰器:父子单向同步

2.2.1 基本介绍

@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。

允许装饰的变量的类型

Object、class、string、number、boolean、enum类型,以及这些类型的数组。

不支持any,支持undefined和null。

支持Date类型。

嵌套类型以及数组中的对象属性无法触发视图更新

2.2.2 简单代码示例

@Entry
@Component
struct Index {
  @State name: string = '父亲'
  @State age: number = 0

  build() {
    Column() {
      Text(`${this.name} : ${this.age}`)
        .width(100)
        .height(50)
        .onClick(() => {
          this.age = 18
        }).backgroundColor(Color.Green)
      Demo({ age: this.age })
    }.width('100%').height('100%')
  }
}


@Component
struct Demo {
  @Prop age: number = 0

  build() {
    Column() {
      Text(this.age.toString())
        .width(100)
        .height(50).backgroundColor(Color.Pink)
    }.width('100%').height('100%')

  }
}

2.3 @Link装饰器:父子双向同步

2.3.1 基本介绍

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

允许装饰的变量类型

Object、class、string、number、boolean、enum类型,以及这些类型的数组。

支持Date类型。嵌套类型以及数组中的对象属性无法触发视图更新

2.3.2 简单代码示例

@Entry
  @Component
  struct Index {
    @State name: string = '父亲'
    @State age: number = 0

    build() {
      Column() {
        Text(`${this.name} : ${this.age}`)
          .width(100)
          .height(50)
          .onClick(() => {
            this.age = 18
          }).backgroundColor(Color.Green)
        Demo({ age: this.age })
      }.width('100%').height('100%')
    }
  }


@Component
  struct Demo {
    @Link age: number

    build() {
      Column() {
        Text(this.age.toString())
          .width(100)
          .height(50).backgroundColor(Color.Pink).onClick(()=>{
            this.age=20
          })
      }.width('100%').height('100%')

    }
  }

2.4 @Provide和@Consume装饰器:与后代组件双向同步

2.4.1 基本介绍

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。

@Provide/@Consume装饰的状态变量有以下特性:

  • @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
  • 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。
  • @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,建议类型相同,否则会发生类型隐式转换,从而导致应用行为异常。

允许装饰的变量类型

Object、class、string、number、boolean、enum类型,以及这些类型的数组。

支持Date类型。

嵌套类型以及数组中的对象属性无法触发视图更新

2.4.2 简单代码示例

@Entry
  @Component
  struct Index {
    @State name: string = '父亲'
    @Provide age: number = 0

    build() {
      Column() {
        Text(`${this.name} : ${this.age}`)
          .width(100)
          .height(50)
          .onClick(() => {
            this.age = 18
          }).backgroundColor(Color.Green)
        Demo()
      }.width('100%').height('100%')
    }
  }


@Component
  struct Demo {
    @Consume age: number

    build() {
      Column() {
        Text(this.age.toString())
          .width(100)
          .height(50).backgroundColor(Color.Pink).onClick(()=>{
            this.age=20
          })
      }.width('100%').height('100%')

    }
  }

2.5 @Observed和@ObjectLink装饰器:嵌套类对象属性变化

2.5.1 基本介绍

上文所述的装饰器仅能观察到第一层的变化,但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。这就引出了@Observed/@ObjectLink装饰器。

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

  • 被@Observed装饰的类,可以被观察到属性的变化;
  • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
  • @Observed用于嵌套类场景中,观察对象类属性变化,要配合自定义组件使用(示例详见嵌套对象),如果要做数据双/单向同步,需要搭配@ObjectLink或者@Prop使用(示例详见@Prop与@ObjectLink的差异)。

允许装饰的变量类型

必须为被@Observed装饰的class实例,必须指定类型。

不支持简单类型,可以使用@Prop。

支持继承Date、Array的class实例

2.5.2 简单代码示例

@Observed
  class People {
    name: string
    age: number
    model: Model

    constructor(name: string, age: number, model: Model) {
      this.name = name
      this.age = age
      this.model = model
    }
  }

@Observed
  class Model {
    like: string = ''

    constructor(like: string) {
      this.like = like
    }
  }

@Entry
  @Component
  struct Index {
    @State p: People = new People('东林', 18, new Model('篮球'))

    build() {
      Column() {
        child({ m: this.p.model }).onClick(() => {
          this.p.model.like = '足球'
        })
      }.width('100%').height('100%')
    }
  }

@Component
  struct child {
    @ObjectLink m: Model

    build() {
      Column() {
        Text(`${this.m.like}`)
          .width(100)
          .height(50)

      }

    }
  }

3. 排行榜小案例

实现如下功能

3.1 代码结构

3.2 Index.ets

import TitleComponent from '../component/TitleComponent'
import TableHeaderComponent from '../component/TableHeaderComponent'
import ItemComponent from '../component/ItemComponent'
import FruitModel from '../model/FruitModel'

@Entry
@Component
struct Index {
  @State fruitModels: FruitModel[] = [new FruitModel('1', '苹果', '10000')
    , new FruitModel('2', '橘子', '9000')
    , new FruitModel('3', '香蕉', '8000')
    , new FruitModel('4', '梨子', '7000')
    , new FruitModel('5', '枣子', '6000')
    , new FruitModel('6', '山竹', '5000')
    , new FruitModel('7', '桃子', '4000')
    , new FruitModel('8', '西瓜1', '3000')
    , new FruitModel('9', '西瓜2', '3000')
    , new FruitModel('10', '西瓜3', '3000')
    , new FruitModel('11', '西瓜4', '3000')
    , new FruitModel('12', '西瓜5', '3000')
    , new FruitModel('13', '西瓜6', '3000')
    , new FruitModel('14', '西瓜7', '3000')
    , new FruitModel('15', '西瓜8', '3000')
    , new FruitModel('16', '西瓜9', '3000')
    , new FruitModel('17', '西瓜10', '3000')
    , new FruitModel('18', '西瓜11', '3000')
    , new FruitModel('19', '西瓜12', '3000')
    , new FruitModel('20', '西瓜13', '3000')
  ]

  /**
   * 刷新数据
   */
  load() {

  }

  build() {
    Column() {
      // 标题
      TitleComponent({ fruitModels: this.fruitModels })
      // 表头
      TableHeaderComponent().margin({ bottom: 20 })
      // 内容
      ItemComponent({ fruitModels: this.fruitModels })
    }
    .height('100%')
    .width('100%')
  }
}

3.3 FruitModel.ets

/**
 * 水果数据类
 */
export default class FruitModel {
  /**
   * 排名
   */
  id: string
  /**
   * 水果名
   */
  name: string
  /**
   * 投票数
   */
  vote: string

  constructor(id: string, name: string, vote: string) {
    this.id = id
    this.name = name
    this.vote = vote

  }
}

3.4 TitleComponent.ets

import AppContext from '@ohos.app.ability.common'
import FruitModel from '../model/FruitModel'

/**
 * 水果排行榜标题组件
 */
@Component
  export default struct TitleComponent{

    @State title:string='水果排行榜'

    @Link fruitModels:FruitModel[]

    build() {

      Row(){
        // 显示返回图标跟标题
        Row(){
          Image($r('app.media.back'))
            .width(30)
            .height(30)
            .margin({right:10})
            .onClick(()=>{
              // 退出当前app
              let context=getContext() as AppContext.UIAbilityContext
              context.terminateSelf()
            })

          Text(this.title)
            .fontSize(30)

        }.width('50%')
          .height(40)
          .justifyContent(FlexAlign.Start)

        // 显示刷新图标
        Row(){
          Image($r('app.media.reset'))
            .height(30)
            .width(30)
            .margin({right:20})
            .onClick(()=>{
              // 刷新数据
              this.fruitModels=[new FruitModel('1','草莓','10000')
                                ,new FruitModel('2','西瓜','9000')
                                ,new FruitModel('3','香蕉','8000')
                                ,new FruitModel('4','梨子','7000')
                                ,new FruitModel('5','枣子','6000')
                                ,new FruitModel('6','山竹','5000')
                                ,new FruitModel('7','桃子','4000')
                                ,new FruitModel('8','西瓜1','3000')
                                ,new FruitModel('9','西瓜2','3000')
                                ,new FruitModel('10','西瓜3','3000')
                                ,new FruitModel('11','西瓜4','3000')
                                ,new FruitModel('12','西瓜5','3000')
                                ,new FruitModel('13','西瓜6','3000')
                                ,new FruitModel('14','西瓜7','3000')
                                ,new FruitModel('15','西瓜8','3000')
                                ,new FruitModel('16','西瓜9','3000')
                                ,new FruitModel('17','西瓜10','3000')
                                ,new FruitModel('18','西瓜11','3000')
                                ,new FruitModel('19','西瓜12','3000')
                                ,new FruitModel('20','西瓜13','3000')
                               ]
            })

        }.width('50%')
          .height(40)
          .justifyContent(FlexAlign.End)
      }
      .width('100%')
        .backgroundColor(Color.Pink)
        .justifyContent(FlexAlign.SpaceBetween)

    }
  }

3.5 TableHeaderComponent.ets

/**
 * 表头组件
 */
@Component
  export default struct TableHeaderComponent {
    build() {
      Row(){
        Text('排名')
          .fontSize(20)
          .width('20%')
          .fontWeight(400)
          .fontColor('#989A9C')

        Text('种类')
          .fontSize(20)
          .width('50%')
          .fontColor('#989A9C')

        Text('得票数')
          .fontSize(20)
          .width('30%')
          .fontWeight(400)
          .fontColor('#989A9C')
      }.width('100%')
        .height(30)
        .backgroundColor(Color.Green)

    }
  }

3.6 ItemComponent.ets

import FruitModel from '../model/FruitModel'

/**
 * 内容主体
 */

@Component
  export default struct ItemComponent {
    /**
   * 水果数据
   */
    @Link fruitModels: FruitModel[]

    build() {
      Column() {
        List({space:20}) {
          ForEach(this.fruitModels, (item: FruitModel) => {
            ListItem() {
              Row() {
                Text(item.id)
                  .fontSize(20)
                  .width('20%')
                  .margin({left:10})
                Text(item.name)
                  .fontSize(20)
                  .width('50%')
                Text(item.vote)
                  .fontSize(20)
                  .width('30%')
              }
              .width('100%')
            }
          })
        }
      }
    }
  }

4. 学习地址

全网首发鸿蒙NEXT星河版零基础入门到实战,2024年最新版,企业级开发!视频陆续更新中!_哔哩哔哩_bilibili

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

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

相关文章

SpringBoot + ITextPdf:高效生成 PDF 预览文件

问过神奇的chatgpt后,了解到iTextPdf这个库,应该是比较好的选择。 解决方案 我们先观察下真实的开票预览的模板。 发票信息由两部分组成: 固定信息,例如购买方信息、销售方信息。 商品信息,可能有多行,需…

基于yolov8的100种中草药智能识别系统python源码+pt模型+训练日志+精美GUI界面

【算法介绍】 基于YOLOv8的100种中草药智能识别系统是一款利用最新的YOLOv8算法开发的高效、准确的识别工具。该系统能够精准快速地识别100种不同的中草药类别,对于传统中药行业是一次重要的革新。 该系统通过搜集不同中草药的相关数据图片,并基于YOLO…

【leetcode】122. 买卖股票的最佳时机 II

题目描述 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。 返回 你能获得的 最大 利润 。…

nacos client 本地缓存问题

问题: nacos 更新了配置文件,更新了以后重新启动还是旧的配置信息。 NACOS版本: 1.1.4 解决: 配置缓存 Nacos Client 会将从 Nacos 服务器获取的配置信息缓存在本地。这样,即使 Nacos 服务器不可用,客…

成都大学体育场馆预约系统—计算机毕业设计源码37087

摘 要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存…

AMD CDNA™2 GPU 中的寄存器压力

Register pressure in AMD CDNA™2 GPUs — ROCm Blogs 注意: 此博客以前是 AMD实验室笔记 博客系列的一部分。 GPU kernel 中的寄存器压力对高性能计算 (HPC) 应用程序的整体性能有着巨大的影响。理解和控制寄存器的使用可以让开发者精心设计代码,以最…

解决银河麒麟中`/etc/sudoers`权限问题

解决银河麒麟中/etc/sudoers权限问题 1、问题描述2、解决方法 💐The Begin💐点点关注,收藏不迷路💐 当你在银河麒麟操作系统中使用sudo命令时,如果遇到“/etc/sudoers可被任何人写”的错误,说明/etc/sudoer…

国庆节快乐

葡萄城在这里祝大家国庆快快乐: 10月葡萄城活动: 公开课 【从软件应用走向数据应用——葡萄城技术赋能数据挖掘】 新版本发布: 活字格 V10.0 Update1新版本发布

Linux相关概念和重要知识点(8)(操作系统、进程属性)

1.操作系统(OS) (1)基本结构的认识 任何计算机系统都包含一个基本的程序集合,用于实现计算机最基本最底层的操作,这个软件称为操作系统。操作系统大部分使用C语言编写,少量使用汇编语言。 从…

【数学分析笔记】第4章第2节 导数的意义和性质(1)

4. 微分 4.2 导数的意义与性质 4.2.1 导数在物理中的背景 物体在OS方向上运动,位移函数为 s s ( t ) ss(t) ss(t),求时刻 t t t的瞬时速度,找一个区间 [ t , t △ t ] [t,t\bigtriangleup t] [t,t△t],从时刻 t t t变到时刻 t…

闭源与开源嵌入模型比较以及提升语义搜索效果的技术探讨

上图为执行语义搜索前的聚类演示 ,嵌入技术是自然语言处理的核心组成部分。虽然嵌入技术的应用范围广泛,但在检索应用中的语义搜索仍是其最常见的用途之一。 尽管知识图谱等可以提升检索的准确率和效率,但标准向量检索技术仍然具有其实用价值…

基于SSM的农产品仓库管理系统【附源码】

基于SSM的农产品仓库管理系统(源码L文说明文档) 目录 4 系统设计 4.1 系统概要设计 4.2 系统功能结构设计 4.3 数据库设计 4.3.1 数据库E-R图设计 4.3.2 数据库表结构设计 5 系统实现 5.1 管理员功能介绍 5.1.1 用户管…

CSS外边距

元素的外边距(margin)是围绕在元素边框以外(不包括边框)的空白区域,这片区域不受 background 属性的影响,始终是透明的。 为元素设置外边距 默认情况下如果不设置外边距属性,HTML 元素就是不会…

通信工程学习:什么是MAC媒体接入控制

MAC:媒体接入控制 MAC(Medium Access Control),即媒体接入控制,是计算机网络中数据链路层的一个重要组成部分,负责协调多个发送和接收站点对一个共享传输媒体的占用。以下是关于MAC的详细解释: …

括号序列C++

题目: 样例解释: 如下几种方案是符合规范的: (**)*() (**(*)) (*(**)) (*)**() (*)(**) 思路: 首先肯定是区间dp,令 dpi,jdpi,j​ 表示从位置 ii 到位置 jj 一共的合法序列总情况数量。 但是不同的形态可能会有不同的转…

【开源项目】CException 为C语言提供简洁高效的异常处理机制

CException:为C语言提供简洁高效的异常处理机制 在C语言中进行异常处理并不像C中那样方便。为了实现高效的异常处理,很多开发者选择了CException,一个基于C标准库 setjmp 和 longjmp 的轻量级异常处理框架。本文将带你了解 CException 的特点…

【Power Query】M函数-List.Sum

M函数-List 列表求和 &#xff08;List.Sum&#xff09;&#xff1a;1&#xff09;横向求和2&#xff09;列求和★思路★</font>★实操★</font> 3&#xff09;求总和4&#xff09;求部分占总体的比重★横向★</font>★竖向★</font> 列表求和 &#x…

C++和OpenGL实现3D游戏编程【连载12】——游戏中音效的使用

1、游戏中音效的使用 前面我们实现了图片纹理的显示功能,是不是感觉到非常的简单。那么今天我们就继续说下游戏声音的实现。音效也是游戏的灵魂,只有搭配了美妙动听的音效以后,游戏才能令人耳目一新,与玩家产生良好的效果。 音效文件最常用的可分为两种,分别为.wav和.mp3…

基于SSM的线上旅行信息管理系统【附源码】

基于SSM的线上旅行信息管理系统&#xff08;源码L文说明文档&#xff09; 目录 4.1 系统概述 4.2 数据库E-R图设计 4.3 数据库表设计 5 系统的实现 5.1 管理员功能模块的实现 5.1.1管理员登录界面 5.1.2用户管理界面 5.1.3景点分类管理界面 5.1.4…

(最新已验证)stm32 + 新版 onenet +dht11+esp8266/01s + mqtt物联网(含微信小程序)上报温湿度和控制单片机(保姆级教程)

物联网实践教程&#xff1a;微信小程序结合OneNET平台MQTT实现STM32单片机远程智能控制 远程上报和接收数据——汇总 前言 之前在学校获得了一个新玩意&#xff1a;ESP-01sWIFI模块&#xff0c;去搜了一下这个小东西很有玩点&#xff0c;远程控制LED啥的&#xff0c;然后我就想…