任务要求
模拟积分抽奖程序,玩家首先输入玩家姓名,跳转到积分抽奖页面,玩家初始积分为1000分,在积分抽奖页面有红黄蓝灰四种卡片,抽中红卡加500分,抽中黄卡加200分,抽中蓝卡减500分,抽到灰卡积分清零。
抽卡规则:
- 仅能抽3次
- 积分清零不能继续
抽卡完毕后可以查看获奖情况:
L3(分数 ==2500):笔记本
L2(分数>=1500):智能手表
L1(分数>0):钥匙扣
L0(分数<=0):未中奖
界面原型:
1)入口页面:
2)抽卡页面:
3)开始抽卡:
4)抽卡结果:
涉及知识点
-
常用属性方法,阴影设置
-
线性布局,边距,内容对齐
-
@Styles、@Extend
-
路由参数传递
-
条件渲染
-
AlertDialog
1 入口页面
界面原型:
1)页面标题
在pages下面新建页面,命名为:ScoreGamePage,清除原有代码,仅留框架代码,然后添加如下代码,完成标题部分:
@Entry
@Component
struct ScoreGamePage {
@State title: string = '积分抽奖'
build() {
Column(){
Text(this.title)
.fontSize(44)
.fontWeight(FontWeight.Bolder)
.margin(20)
}
.width('100%')
.height('100%')
}
}
预览效果:
2)布局【好运连连】部分
使用Row布局,【好运】占一行,【连连】占一行。
build() {
Column({ space: 10 }) {
Text(this.title)
...
Row({ space: 10 }) {
Text('好')
.squareTxt(Color.Red)
Text('运')
.squareTxt(Color.Yellow)
}
Row({ space: 10 }) {
Text('连')
.squareTxt(Color.Blue)
Text('连')
.squareTxt(Color.Gray)
}
}
.width('100%')
.height('100%')
}
}
使用@Extend定义全局样式(需要写在组件外面):
@Extend(Text)
function squareTxt(color: Color) {
.fontSize(50)
.width(150)
.height(150)
.borderRadius(12)
.backgroundColor(color)
.textAlign(TextAlign.Center)
.shadow({radius:8,color:'#ccc',offsetX:20,offsetY:20})
}
[!NOTE]
关于@Extend
1、扩展原生组件
2、属于全局样式,需在组件外定义,必须加function
3、可以传递参数
4、仅可使用所扩展组件的属性方法和所有组件的通用属性方法
预览效果:
3)输入玩家名及开始抽奖按钮
继续添加文本输入框和按钮:
TextInput({placeholder:'请输入您的名字'})
.width('95%')
.margin(20)
Button('开始抽奖')
.width('95%')
.height(50)
.fontSize(22)
预览效果:
2 抽奖页面
界面原型:
1)新建页面,在pages下面新建页面,命名为:StartScoreGamePage,清理原有代码,然后使用Column布局页面:
@Entry
@Component
struct StartScoreGamePage {
build() {
Column() {
}
.height('100%')
.width('100%')
}
}
2)布局统计栏
显示玩家名、分数、剩余次数。
build() {
Column() {
Text('Jerry:得分:1000,剩余次数:3')
.titleBarTxtStyle()
}
.height('100%')
.width('100%')
定义样式:
@Extend(Text) function titleBarTxtStyle(){
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Green)
.width('95%')
.height(80)
.backgroundColor('#f1f3f5')
.borderRadius(8)
.textAlign(TextAlign.Center)
.margin(10)
}
预览效果:
3)卡片区域布局
布局红黄卡片,在一个Row布局中包含一个Column布局,上面显示图片,下面显示文本:
//卡片区域
Row({space:5}){
Column({space:5}){
Image($r('app.media.redcard'))
.borderColor(Color.Red)
.cardStyle()
Text('红卡')
.cardTitleStyle(Color.Red)
}
Column({space:5}){
Image($r('app.media.yellowcard'))
.cardStyle()
.borderColor(Color.Yellow)
Text('黄卡')
.cardTitleStyle(Color.Yellow)
}
}
.margin(5)
卡片图片部分样式封装,使用@Styles:
@Styles cardStyle(){
.width('40%')
.height('25%')
.borderRadius(18)
.borderWidth(4)
}
[!NOTE]
写在组件内
卡片标题样式封装,使用@Extend,写在组件外:
@Extend(Text) function cardTitleStyle(color:Color){
.fontSize(22)
.fontWeight(FontWeight.Bold)
.fontColor(color)
.margin({top:5})
}
预览效果:
使用同样布局,布局蓝卡和灰卡,代码基本类似:
Row({space:5}){
Column({space:5}){
Image($r('app.media.bluecard'))
.borderColor(Color.Blue)
.cardStyle()
Text('蓝卡')
.cardTitleStyle(Color.Blue)
}
Column({space:5}){
Image($r('app.media.graycard'))
.cardStyle()
.borderColor(Color.Gray)
Text('灰卡')
.cardTitleStyle(Color.Gray)
}
}
.margin(5)
预览效果:
4)触发按钮
添加【我要抽卡】和【抽奖结果】按钮:
// 触发按钮
Button('我要抽卡').width('80%').height(50).fontSize(25)
Button('抽奖结果').width('80%').height(50).fontSize(25)
.backgroundColor(Color.Orange)
[!NOTE]
注意调整按钮组件父容器设置组件间间隙,此处设置为5
预览效果:
3 显示玩家数据
1)替换标题中的硬编码
我们需要修改状态栏中的信息,不再使用硬编码,能够获取玩家名称,得分和剩余次数。
玩家名称需入口页面通过路由参数的方式进行获取,当前得分默认1000分,剩余次数默认3次。
首先定义所需变量:
@State playerName: string = '匿名'
@State score:number = 1000
@State times:number = 3
替换状态栏硬编码:
//Text('Jerry:得分:1000,剩余次数:3')
Text(`${this.playerName}:得分:${this.score},剩余次数:${this.times}`)
.titleBarTxtStyle()
预览效果:
2)通过路由传递参数
修改入口页面,通过路由传递参数,首先在ScoreGamePage中定义变量保存玩家名:
@State playerName: string = ''
为输入框绑定事件,获取输入的玩家名:
TextInput({placeholder:'请输入您的名字'})
.width('95%')
.margin(20)
//绑定玩家名
.onChange((value)=>{
this.playerName = value
})
为开始抽奖按钮绑定事件进行路由跳转,并传递玩家名,初始分数,次数等:
Button('开始抽奖')
.width('95%')
.height(50)
.fontSize(22)
.onClick(() => {
router.pushUrl({
url: 'pages/StartScoreGamePage',
params: {
// 路由参数传递
playerName: this.playerName,
initScore: 1000,
times: 3
}
})
})
在StartScoreGamePage组件前面定义路由参数接口:
//定义路由参数接口
interface MyRouterParams {
playerName: string, //玩家名
initScore: number, // 初始分数
times: number //抽奖次数
}
在组件头部变量处改为从路由参数中获取:
//@State playerName: string = '匿名'
@State playerName: string = (router.getParams() as MyRouterParams).playerName
@State score: number = (router.getParams() as MyRouterParams).initScore
@State times: number = (router.getParams() as MyRouterParams).times
[!NOTE]
更多路由api请参考:
预览效果:
点击开始抽奖按钮后进行跳转:
4 实现抽卡功能
1)产生随机数模拟抽卡
抽卡规则:
1:红卡积分加500
2:黄卡积分加200
3:蓝卡积分减500
4:灰卡积分清零
首先在StartScoreGamePage中定义变量保存抽到的卡编号:
@State cardNum: number = 0;//抽到的卡编号
然后添加函数随机产生卡片编号:
genCardNumber(max:number,min:number){
let range = max - min;
let rand = Math.random();
this.cardNum = min + Math.round(range * rand);//四舍五入
if(this.cardNum == 1){
this.score += 500;//红卡积分加500
}
if(this.cardNum == 2){
this.score += 200;//黄卡积分加100
}
if(this.cardNum == 3){
this.score -= 500;//蓝卡积分减50
}
if(this.cardNum == 4){
this.score = 0;//灰卡积分清零
}
console.info('cardNum:'+this.cardNum +':score:'+this.score)
}
2)实现抽卡
继续添加函数,实现积分和抽卡次数判断,显示抽卡结果:
drawCard(){
this.times--
let msg = ''//对话框提示卡片抽取信息
//次数和积分同时不为零可以继续
if (this.times >= 0 && this.score > 0) {
this.genCardNumber(1, 4)
if (this.cardNum == 1) {
msg = '恭喜您:),您抽到了红卡,积分+500!'
}
if (this.cardNum == 2) {
msg = '恭喜您:),您抽到了黄卡,积分+200!'
}
if (this.cardNum == 3) {
msg = '很遗憾:(,您抽到了蓝卡,积分-500!'
}
if (this.cardNum == 4) {
msg = '很遗憾:(,您抽到了灰卡,积分清零!'
}
AlertDialog.show({
title: '提示',
message: msg,
confirm:{
value:'关闭',
action:()=>{
console.info('confirm callback')
}
},
cancel:()=>{
console.info('cancel callback')
}
})
}else{
//次数用完
if(this.times <0 ){
this.times = 0
msg = '您的抽卡次数已用尽:('
}else{
this.times = 0
msg = '很遗憾,您的积分已用尽,下次再来:('
}
AlertDialog.show({
title: '提示',
message: msg,
confirm:{
value:'关闭',
action:()=>{
console.info('confirm callback')
}
},
cancel:()=>{
console.info('cancel callback')
}
})
}
}
[!NOTE]
AlertDialog参考api:
3)将函数绑定到【我要抽卡】按钮:
// 触发按钮
Button('我要抽卡').width('80%').height(50).fontSize(25)
.onClick(()=>{
this.drawCard()
})
4)功能验证
仍然从入口页面开始预览:
输入名字后继续:
点击我要抽卡按钮:
积分清零后不可再次抽卡:
<img src="转存失败,建议直接上传图片文件 assets/image-20250319144947006.png" alt="image-
5 结果展示
1)新建页面命名为:ScoreGameResultPage,用于展示抽奖结果,删除多余代码,仅留骨架代码:
@Entry
@Component
struct ScoreGameResultPage {
build() {
}
}
2)根据中奖等级展示中奖结果图片
首先定义中奖等级,然后在build函数中使用条件渲染展示获奖文字和图片:
@Entry
@Component
struct ScoreGameResultPage {
@State gradeLevel: number = 1//中奖等级
build() {
Column({space:10}){
if(this.gradeLevel ==3){
Text('恭喜您,您抽到笔记本一个!')
.fontSize(22)
.fontWeight(FontWeight.Bold)
Image($r('app.media.note'))
.width(200)
.height(200)
.borderRadius(8)
}else if(this.gradeLevel ==2){
Text('恭喜您,您抽到手表一个!')
.fontSize(22)
.fontWeight(FontWeight.Bold)
Image($r('app.media.watch'))
.width(200)
.height(200)
.borderRadius(8)
}else{
Text('恭喜您,您抽到钥匙扣一个!')
.fontSize(22)
.fontWeight(FontWeight.Bold)
Image($r('app.media.yaoshikou'))
.width(200)
.height(200)
.borderRadius(8)
}
}
.width('100%')
.height('100%')
}
}
预览效果:
3)完成结果查看功能
在StartScoreGamePage页面继续编码,首先定义中奖级别:
@State gradelevel: number = 0; // 中奖级别
然后定义结果展示函数:
代码逻辑:
- 次数未用尽,不可查看结果
- 分数==2500,gradeLevel=3
- 分数>=1500,gradeLevel=2
- 分数>0,gradeLevel=1
- 分数<=0,gradeLevel=0 未中奖
- 未中奖不可查看奖品
- 其他情况进行路由跳转,进入查看奖品页面
编写函数showResult():
//显示中奖结果,根据中奖级别进行跳转页面
showResult(){
if(this.times >0){
AlertDialog.show({
title: '提示',
message: '您还没有抽完奖,不能查看结果!!!',
confirm:{
value:'关闭',
action:()=>{
console.info('confirm callback')
}
},
cancel:()=>{
console.info('cancel callback')
}
})
return
}
if(this.score == 2500){
this.gradelevel = 3
}
else if(this.score >= 1500){
this.gradelevel = 2
}
else if(this.score > 0){
this.gradelevel = 1
}
else{
this.gradelevel = 0
}
if(this.gradelevel == 0){
AlertDialog.show({
title: '提示',
message: '您没有抽中任何奖品,下次再来!!!',
confirm:{
value:'关闭',
action:()=>{
console.info('confirm callback')
}
},
cancel:()=>{
console.info('cancel callback')
}
})
return
}
router.pushUrl({
url:'pages/ScoreGameResultPage',
params:{
gradeLevel: this.gradelevel
}
})
}
}
在抽奖按钮上绑定事件:
Button('抽奖结果').width('80%').height(50).fontSize(25)
.backgroundColor(Color.Orange)
.onClick(()=>{
this.showResult()//显示中奖结果
})
在ScoreGameResultPage页面处理路由参数,首先定义接口:
//定义路由参数接口
interface ReultRouterParams {
gradeLevel: number // 中奖结果
}
从路由中获取参数:
@State gradeLevel: number = (router.getParams() as ReultRouterParams).gradeLevel
4)功能验证:
从入口页面进入游戏:
点击开始抽奖:
点击我要抽卡:
继续点击我要抽卡,直到抽奖完成:
点击抽奖结果:
代码仓:
##鸿蒙应用开发 ##鸿蒙游戏 ##休闲娱乐