一大波女生、男生适用的最新鸿蒙练手案例来袭
介绍
以下案例适合刚开始手鸿蒙开发的小伙伴,有大量的最新逻辑锻炼、鸿蒙核心语法、使用最新鸿蒙的@Local、@Computed 等装饰器来完成。
另外,考虑在学习知识的知识时候,优先关注核心功能,所以提供的布局都会适当简化,但是能保证把核心功能展示出来。
每一个案例会点出终点和核心知识,让学习者可以练习完毕,可以得到什么。
学习的路线
- 先看效果
- 复现效果
- 如果有对代码产生的疑问,可以在评论区内直接提出,有疑问,必回复
- 如果能帮助到你,就很好了。😄
点击高亮
- 练习基本的线性布局
- 练习基本的数组使用
- 练习列表渲染语法 ForEach
- 练习布局中的状态切换 三元表达式
- 掌握通用的点击高亮
@Entry @ComponentV2 struct Index { @Local list: string[] = ["小明", "小红", "小黑", "小黄"] // 声明一个数字 表示你当前选中的按钮的下标 @Local select: number = 1 build() { Column() { ForEach(this.list, (item: string, index: number) => { Button(item + " " + (this.select == index)) .backgroundColor(this.select == index ? "#ffcd43" : "#007dfe") .onClick(() => { this.select = index }) }) } .width("100%") .height("100%") .padding({ top: 100 }) } }
待办列表
- 新手上手新的编程语言的必做案例 crud - 增删该查
- 练习 V2装饰器、@Local、@Computed、事件等
- 打通 状态 -> UI 、 UI-> 状态 的一些交互
@ObservedV2 class Task { @Trace task: string = "" @Trace isFinished: boolean = false } @Entry @ComponentV2 struct Index { // 任务列表 @Local list: Task[] = [ // { task: "数组学习", isFinished: true }, // { task: "函数学习", isFinished: false } ] // 输入框输入的内容 @Local inpValue: string = "" // 未完成数量 @Computed get statistics() { let undoneNum = this.list.filter(v =>!v.isFinished).length let doneNum = this.list.length - undoneNum return [undoneNum, doneNum] } // 清理已经完成的任务 onClear = () => { // 筛选 留下未完成 this.list = this.list.filter((v =>!v.isFinished)) } // 删除 onDelete = (index: number) => { this.list.splice(index, 1) } build() { Column() { Row() { Button("清理已完成") .onClick(this.onClear) } Row() { Text(`未完成的数量 ${this.statistics[0]}`) Text(`完成的数量 ${this.statistics[1]}`) } .width("80%") .justifyContent(FlexAlign.SpaceAround) Row() { TextInput() .width(200) .onChange(value => { this.inpValue = value }) Button("确认") .onClick(() => { // 熟练 探囊取物!! // 先判断当前任务有没有出现过 const isExit = this.list.some(element => element.task == this.inpValue) if (!isExit) { const p = new Task() p.task = this.inpValue this.list.push(p) } }) } ForEach(this.list, (item: Task, index: number) => { Row() { Text(item.task) .fontColor(item.isFinished ? "#666" : "#000") .decoration({ type: item.isFinished ? TextDecorationType.LineThrough : TextDecorationType.None }) .fontStyle(item.isFinished ? FontStyle.Italic : FontStyle.Normal) .onClick(() => { this.onDelete(index) }) Button(item.isFinished ? "继续" : "完成") .backgroundColor(item.isFinished ? "#ffa601" : "#007dfe") .onClick(() => { this.list[index].isFinished = !this.list[index].isFinished }) } }) } .width("100%") .height("100%") .padding({ top: 100 }) } }
B站显示更多
- 练习Flex布局的换行
- 练习Scroll布局的水平滚动
- 练习绝对定位-水平居中
- 练习条件渲染
@Entry @ComponentV2 struct Index { @Local list: string[] = ["首页", "动画", "番剧", "国创", "音乐", "舞蹈", "游戏", "知识", "科技", "运动", "汽车", "生活", "美食", "动物圈", "鬼畜", "时尚", "娱乐", "影视", "纪录片", "电影", "电视剧", "直播", "课堂"] // 是否显示更多 @Local isShowMore: boolean = false build() { Column() { Row({ space: 5 }) { Scroll() { // true 换行 Flex({ wrap: this.isShowMore ? FlexWrap.Wrap : FlexWrap.NoWrap }) { ForEach(this.list, (item: string) => { Text(item) .margin(10) }) } } .scrollable(ScrollDirection.Horizontal) .layoutWeight(1) // .backgroundColor(Color.Yellow) .padding({ bottom: this.isShowMore ? 30 : 0 }) if (this.isShowMore) { Image($r("app.media.app_icon")) .width(20) .position({ left: "50%", bottom: 0 }) .translate({ x: -10 }) .onClick(() => { this.isShowMore = !this.isShowMore }) } else { Image($r("app.media.app_icon")) .width(20) .onClick(() => { this.isShowMore = !this.isShowMore }) } } .width("100%") .backgroundColor(Color.Red) } .width("100%") .height("100%") } }
仿考研日程
- 练习如何根据需求来拆分数据
- 简单的渲染
// 二级目录 interface SubContent { subTitle: string subContent: string } // 一级目录 interface OneContent { title: string content: SubContent[] } @Entry @ComponentV2 struct Index { @Local list: OneContent[] = [ { title: "统考", content: [ { subTitle: "国家线", subContent: "2024。。。。" }, { subTitle: "考研复试流程图", subContent: "" } ] }, { title: "统考22", content: [ { subTitle: "国家线22", subContent: "2024。。。。22" }, { subTitle: "考研复试流程图22", subContent: "" } ] } ] // 选中标题的下标 @Local current: number = 0 build() { Column() { // 1 标题 Row({ space: 10 }) { ForEach(this.list, (item: OneContent, index: number) => { Text(item.title) .fontColor(this.current == index ? "#0094ff" : "#000") .onClick(() => { this.current = index }) }) } // 2 内容 Column() { ForEach(this.list[this.current].content, (item: SubContent) => { Column() { Text(item.subTitle) Text(item.subContent) } }) } } .width("100%") .height("100%") .backgroundColor("#eee") } }
仿vantUI -倒计时
- 练习定时器
- 练习一点关于时间处理的逻辑功能
@Entry @ComponentV2 struct Index { @Local str: string = "" // 时间 毫秒 time: number = 5 * 60 * 60 * 1000 tid: number = -1 build() { Column() { Button("开始倒计时") .onClick(() => { // setInterval 时间间隔最少 是10ms this.tid = setInterval(() => { this.time -= 10 // 计算小时 整数 parseInt Math.floor() // parseInt 只能传递字符串类型 const hour = Math.floor(this.time / 1000 / 60 / 60) const minute = Math.floor(this.time / 1000 / 60 % 60) const seconde = Math.floor(this.time / 1000 % 60) const milliSeconde = this.time % 1000 this.str = `${hour}:${minute}:${seconde}.${milliSeconde}` }, 10) }) Button("暂停") .onClick(() => { clearInterval(this.tid) }) Text(this.str) .fontSize(30) } } }
仿掘金抽奖
- 练习flex布局-换行
- 练习随机数
- 练习数组+随机数实现随机获取元素
@Entry @ComponentV2 struct Index { @Local list: string[] = [ "4090", "4399", "大彩电", "iphone16", "meta70", "Mac", "小牛电动车", "迪拜7日游", "北京房子一套" ] @Local current: number = 0 // 根据下标设置奖品高亮 setHighline(index: number) { this.current = index } build() { Column() { Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.list, (item: string, index: number) => { Text(item) .width("33.33%") .padding({ top: 20, bottom: 20 }) .border({ width: 1 }) .backgroundColor(this.current == index ? "#e37815" : "#fff") }) } Button("开始抽啦") .onClick(() => { // 开始抽奖 let tid = setInterval(() => { // 等于 数组长度范围内的随机数 const index = Math.floor(Math.random() * this.list.length) this.setHighline(index) }, 10) // 开启5s种延时器 - 停止定时器 setTimeout(() => { clearInterval(tid) }, 5000) }) } } }
仿掘金抽奖 - 不重复抽奖
- 加强逻辑处理,如何实现不重复抽奖
- 练习一些数组的方法
- 练习使用 @Computed
@Entry @ComponentV2 struct Index { @Local list: string[] = [ "4090", "4399", "大彩电", "iphone16", "meta70", "Mac", "小牛电动车", "迪拜7日游", "北京房子一套" ] @Local selectedList: number[] = [] @Local current: number = 0 // 奖池 @Computed get newList() { const newList: number[] = [] for (let index = 0; index < this.list.length; index++) { let item = this.selectedList.find(v => v === index) if (!item) { newList.push(index) } } return newList } // 根据下标设置奖品高亮 setHighline(index: number) { this.current = index } build() { Column() { Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.list, (item: string, index: number) => { Text(item) .width("33.33%") .padding({ top: 20, bottom: 20 }) .border({ width: 1 }) .backgroundColor( this.selectedList.includes(index) ? "#e37815" : (this.current == index ? "#e37815" : "#fff")) }) } Button("开始抽啦") .onClick(() => { // 开始抽奖 let tid = setInterval(() => { // 等于 数组长度范围内的随机数 const index = Math.floor(Math.random() * this.newList.length) this.setHighline(this.newList[index]) }, 10) // 开启5s种延时器 - 停止定时器 setTimeout(() => { clearInterval(tid) this.selectedList.push(this.current) }, 1000) }) } } }
仿vantUI-分页组件-简单版本
- 练习基本的鸿蒙线性布局
- 练习条件渲染
- 练习逻辑能力
@Entry @ComponentV2 struct Index { @Local list: string[] = ['1', '2', '3', '4', '5'] @Local current: number = 4 build() { Column() { Row({ space: 2 }) { Button("上一页") .enabled(this.current != 0) .backgroundColor("#fff") .fontColor("#0094ff") .stateStyles({ disabled: { .backgroundColor("#eee") } }) .onClick(() => { this.current-- }) ForEach(this.list, (item: string, index: number) => { Button(item) .backgroundColor(this.current == index ? "#0094ff" : "#fff") .fontColor(this.current == index ? "#fff" : "#0094ff") .onClick(() => { this.current = index }) }) Button("下一页") .enabled(this.current != this.list.length - 1) .backgroundColor("#fff") .stateStyles({ disabled: { .backgroundColor("#eee") } }) .fontColor("#0094ff") .onClick(() => { this.current++ }) } } .width("100%") .height("100%") .padding({ top: 100 }) .backgroundColor("#eee") } }
仿vantUI-分页组件-复杂版本
- 练习基本的鸿蒙线性布局
- 练习条件渲染
- 练习复杂的逻辑能力
@Entry @ComponentV2 struct Index { @Local list: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] @Local test: number = 1 @Local showList: number[] = [1, 2, 3] change() { if (this.test > 1 && this.test < this.list.length) { this.showList = [this.test - 1, this.test, this.test + 1] } } previous() { this.test-- this.change() } next() { this.test++ this.change() } build() { Column() { Row() { Button("上") .enabled(this.test != 1) .backgroundColor("#ccc") .onClick(() => { this.previous() }) if (this.test > 2) { Button("...") .backgroundColor("#ccc") .onClick(() => { this.previous() }) } ForEach(this.showList, (item: number) => { Button(item.toString()) .backgroundColor(this.test == item ? Color.Blue : "#ccc") .onClick(() => { this.test = item this.change() }) }) if (this.test < this.list[this.list.length-1] - 1) { Button("...") .backgroundColor("#ccc") .onClick(() => { this.next() }) } Button("下") .enabled(this.test != this.list[this.list.length-1]) .backgroundColor("#ccc") .onClick(() => { this.next() }) } } } }
小结
如果部分内容中的图片不存在,自己随机替换即可。