一、书中致谢&前言
2021年6月29日23:10:32
- 51CTO鸿蒙技术社区很有用
- 本书使用DevEoc中的平台为Lite Wearable,即轻量级的可穿戴产品的开发
- 本书介绍的是一个呼吸训练系统APP的开发全过程,
- 采用 项目导向的方式 和 任务导向的方式 ,共计36个任务每个任务分为3个部分,包括运行效果、实现思路、代码详解。
- 本书三章,第一章为“鸿蒙操作系统简介”;第二章为“项目准备工作”;第三章为“呼吸训练实战项目”
- 代码下载网址
这代码使用的DevEco版本太老了!!!
二、学习完本书后自己总结的提示和建议
- Lite wearable和wearable所适用的API不一样!开始之前请在config.json-deviceTypel里确定自己所在的项目是Lite wearable。
- 同理!canvas画布组件同样在Lite wearable不支持!使用chart就行
- 同理!关于滑动事件。direction的值比之老版本有改变,各位读者请注意,up和down不可用,应用top和bottom来表示上下。
- 在预期效果达不到的时候,多用console.log(“XXXX”);打印信息,来查看函数是否如期调用。
- 动态数据绑定在本APP中使用极多,不管是出于显示和数据的分离作用,还是通过动态数据简化代码。都极其好用。在JS-dada中规定字典(值、数组)的格式请注意。
- 主页面是布局和图片旋转、倒计时页面是页面跳转、压力占比页面是进度器应用、心率页面是线形图的应用、活动页面是柱状图的应用、压力分布页面是2d绘制引擎的应用(但canvas不能用在Lite wearable,用的还是chart)、最大摄氧量页面是弧形进度的应用、学习交流页面就是贴图。
- 用params指定要传递的数据。
- 容器与组件的应用还需要更多的案例去熟悉,最终期望到达熟稔于心的地步。包含组件与组件、组价与容器。
- 随机数组,随机数的生成,应成为定式记住。
- 图片的选择image、src。
- 书中和资料上的代码都没有格式化,我觉得这样不好,ctrl+alt+L就代码格式化了,方便查看、方便阅读、方便修改。
- 页面与页面的跳转(router-uri)-URI最准确的是在config.json-Page里面看,书中的跟实际的不太一样
- 通过style属性中的animation-duration样式指定logo图片转动一次的时间,通过style属性中的animation-ireration-count样式指定logo图片转动
- 参数、形参、实参、this、自定义函数、函数调用、函数定义、逗号、冒号、循环语句、选择语句、求最大、求最小、属性值
三、第一章 鸿蒙操作系统简介
- 时间:2021年6月29日23:28:46
- 1.1 1+8+N全场景
- 其实也就是,构建一个基于鸿蒙生态下的IoT
- 1.2 分布式(理解:多个人干多个活儿)
- 分布式软总线与传统意义上的硬总线的区别,分布式软总线承担了任务总线、数据总线、总线中枢。任务总线:负责将应用程序在多个终端上快速分发;数据总线:负责数据在设备间的高性能分发和同步;总线中枢:负责将应用程序控制,用于自动发现并组网,以及维护设备间的拓扑关系。
- 鸿蒙操作系统的分布式软总线可以实现异构融合网络
- 分布式数据管理也是鸿蒙操作系统的核心技术
四、第二章 项目准备工作
- 时间:2021年7月3日23:16:46
2.1 搭建开发环境(已通过之前的学习已经成功搭建)
- 2.11安装Node.js
- 2.1.2安装DevEco Studio
2.2Hello World
- 注意一个previewer就行
- 每个页面都包含一个hml文件(结构)、一个css文件(样式)、一个js文件(行为)
- 具体的来讲就是,hml文件是页面的结构,用于描述页面中包含哪些组件;css文件是页面的样式,用于描述页面中的组件都长什么样子;js文件是页面的行为,用于描述页面中的组件是如何进行交互的
- index.js 中定义了一个变量title,它的值是‘World’,是个占位符,在程序的运行过程中动态确定的,这种技术称之为动态数据绑定
五、第三章 呼吸训练实战项目
- 时间:2021年7月5日15:50:28
- 综述:对于整个APP的一个介绍
3.1任务1:在主页面中添加一个按钮并响应其单击事件
- 时间:2006年7月6日14:17:12
- 调试了一下午发现由于书籍用的DevEco版本太低了,导致有很多不一样,以至于运行不了。
- 要实现的效果:构建点我的页面
- 时间:2021年7月7日14:12:47
- 经过更新DevEco Studio 2.2.0.200 x64
- border-bottom-width
- width
上述两者不一样,经过调试已经可以得出界面
时间:2021年7月7日20:46:39
对位置进行调整
单击该按钮后打印一条log
在编程过程中,
- //index.js
- //定义clickAction函数
- onInit() {
- this.title = this.$t('strings.world');
- },
- clickAction(){
- console.log("我被单击了");
- }
要用,隔开,分号的英文还是中文很重要
- //index.hml
- //按钮的onclick单击事件
- <input type="button" value="点我" class="btn" onclick="clickAction" />
编译器右上角有个小虫子,是Debug按钮(Shift+9),要想看到打印就需要Debug
非模式的浮动窗口
因为教材使用的是Litewearable而现在2.2版本的DevEco都是Wearable了。所以不能用previewer了,就只能用远程虚拟机Device Manager
成功运行
3.2任务2:添加训练页面并实现其与主页面之间的相互跳转
时间:2021年7月7日21:17:59
分析:行为相似,稍作改变,可以调用router.replace()语句实现页面间的跳转,在调用该语句的时候通过Uri指定目标页面的地址
创建JS页面
进行跳转
时间:2021年7月7日22:30:45
经过不断试错,加上console.log的提示发现,训练页面可以跳转主页面,但主页面无法跳转训练页面。
经过半个多小时的调试(误入歧途,妄想通过更改config.json中的deviceType来实现wearable到litewearable的转化),之前一直想的是因为previewer自身的问题,认为无法跳转是因为项目本身是wearable的,而不是Litewearable的导致了认知偏差,完全没有想到是uri出了问题。
最后完成的效果如下GIF
3.3任务3:验证应用和每个页面的生命周期事件
该任务的目的就是通过打印生命周期各个阶段的名称,来感受每个页面的生命周期
时间:2021年7月7日22:43:05
生命周期(onInit-onReady-onShow-onDestroy)
- onInit() {
- console.log("主页面的onInit()正在被调用");
- router.replace({
- uri:'pages/index/index'
- });
- },
- onReady() {
- console.log("主页面的onReady()正在被调用");
- },
- onShow() {
- console.log("主页面的onShow()正在被调用");
- },
- onDestroy() {
- console.log("主页面的onDestroy()正在被调用")
- }
其具体实现
3.4 任务4:在主页面中显示logo和两个选择器
时间:2021年7月7日23:09:03
思路:使用Image组件显示鸿蒙呼吸训练的logo。使用picker-view组件显示logo左右两边的选择器。
关于copy图片的hm.png的问题卡了一阵子
之后是关于图片与按钮的自适应问题调试了一阵子
时间:2021年7月7日23:47:20
时间:2021年7月8日14:18:57
卡了太久太久了。从上午到下午,不过有经验了,以后有问题从开发文档进行查询答案。
下午下课问了四个实训老师,还是存在问题
时间:2021年7月8日23:29:21
在51CTO学院张荣超老师的企业微信群里问了问题,希望可以得到解答
时间:2021年7月8日23:44:47
张荣超老师回复!发了源码,我进行研究研究。
终于解决了!!!!
时间:2021年7月9日00:59:21
存在两个问题:
1.app.js中引号的问题
Litewearable的JS API与wearable的API不兼容。,所以我把config.json改了
最后修改后的页面
3.5 任务5:在指定选择器的默认选中项并获取选中项的值
时间:2021年7月9日09:09:54
range的类型:Array
使用时需要使用数据绑定的方式,如range = {{data}},js中声明相应变量:data:[“15”, “20”, “25”]。
selected的相关说明:
selected:设置文本选择器的默认选择值,该值需要为range的索引。
设置时间选择器的默认取值,格式为 HH:mm;
change的说明:
在使用的时候要用onchange
文本选择器选定值后触发该事件。参数:{ newValue: newValue, newSelected: newSelected }
时间选择器选定值后触发该事件。参数:{ hour: hour, minute: minute}
- changeAction1(pv) {
- console.log("左边的选中项:" + pv.newValue);
- },
- changeAction2(pv) {
- console.log("右边的选中项:" + pv.newValue);
- },
3.6 任务6:将主页中选择器的值传递到训练页面
时间:2021年7月9日14:35:07
页面跳转的时候:用uri指定目标页面,用params指定要传递的数据。
在生命周期事件函数onInit()中获取主页面传递过来党的值,并将其打印到log中,因为选择器的值存放在了一个字典中,并且对应的key分别是data1和data2,所以训练页面中可以通过this.data1获取传递过来的左边选择器的值,右边同理。
- console.log("接收到的左边选择器的值:" + this.data1);
- console.log("接收到的右边选择器的值:" + this.data2);
3.7 任务7:修改主页面和训练页面中按钮的文本及样式
时间:2021年7月9日14:52:17
对font-size样式修改按钮的文本大小
通过background-color样式修改按钮的背景颜色
通过border-color样式修改按钮的边框颜色
按钮颜色还挺好看的
training页面的按钮同理
3.8 任务8:在训练页面显示总共需要坚持的秒数
时间:2021年7月9日15:03:43
因为training页面需要显示主页面选择器选择的值作为参数,所以这里需要采用动态绑定的方式。
- picker1value = this.key1;
- picker2value = this.key2;
- if (picker1value == "1") {
- picker1seconds = 60;
- } else if (picker1value == "2") {
- picker1seconds = 120;
- } else if (picker1value == "3") {
- picker1seconds = 180;
- }
- if (picker2value == "较慢") {
- picker2seconds = 6;
- } else if (picker2value == "舒缓") {
- picker2seconds = 4;
- } else if (picker2value == "较快") {
- picker2seconds = 2;
- }
- this.seconds = picker1seconds;
这里比较笨拙可以用
- picker1seconds=picker1value*60;
3.9 任务9:在训练页面倒计时显示再坚持的秒数
时间:2021年7月9日15:23:13
在训练页面的生命周期事件函数onShow()中调用==setInterval()==函数创建一个定时器,并在调用时指定定时器要执行的动作及其时间间隔
- run1() { this.seconds--; if (this.seconds == 0) { clearInterval(timer1); timer1 = null; this.isShow = false; }},
3.10 任务10:再坚持的秒数在倒计时结束时隐藏显示的文本
时间:2021年7月9日15:33:33
将某个组件的show属性的值设置为false从而隐藏该组件
注意:隐藏组件之后,它在页面中所占的空间仍然存在
- seconds: 0,//这个,必须要加上isShow:truetimer1 = setInterval(this.run1, 1000);
3.11 任务11:在训练页面根据呼吸节奏交替显示“吸气”和“呼气”
时间:2021年7月9日15:38:36
在training页面交替显示,就需要在training页面的生命周期函数onShow()中调用==setInterval()==创建一个定时器,并在调用时指定定时器要执行的动作及其时间间隔。
因为我们设定了较慢、舒缓、较快,所以这里有一个节奏的转换,也就是说要用不同的时间间隔区别不同的selected的选择
需要声明一个全局变量counter作为计时器,将其初值设置为0
- run2() { counter++; if (counter == picker1seconds / picker2seconds) { clearInterval(timer2); timer2 = null; this.breath = "已完成"; } else { if (this.breath == "吸气") { this.breath = "呼气"; } else if (this.breath == "呼气") { this.breath = "吸气"; } }},
3.12 任务12:每次吸气或呼气时都实时显示进度百分比
时间:2021年7月9日16:18:34
还是使用定时器
- run3() { this.percent = (parseInt(this.percent) + 1).toString(); if (parseInt(this.percent) < 10) { this.percent = "0" + this.percent; } if (parseInt(this.percent) == 100) { this.percent = "0"; } if (timer2 == null) { clearInterval(timer3); timer3 = null; this.percent = "100"; }},
3.13 任务13:每次吸气或呼气时logo都顺时针转动一周
时间:2021年7月9日17:13:22
通过style属性中的animation-duration样式指定logo图片转动一次的时间,通过style属性中的animation-ireration-count样式指定logo图片转动
logo顺时针转动一周的时间,就是一次呼气或吸气的时间picker2secons,但是对于training.hml中的animation-duration样式,要指定其点位“s”,因此要将picker2seconds+“s”赋值给data中的duration。
logo转动的次数就是吸气和呼气的总次数,即picker1seconds/picker2seconds。
时间:2021年7月10日09:14:02
排查了很久为什么图片转不起来
原因居然在这里:
可恶!
终于成功了!
3.14 任务14:添加倒计时页面并实现由主页向其跳转
时间:2021年7月10日09:17:46
就是创建新页面。新布局,新组件
3.15 任务15:在倒计时页面进行训练指引的3秒倒计时
时间:2021年7月10日09:25:24
- run() { counter = counter - 1; if (counter != 0) { this.imgsrc = "/common/images/" + counter.toString() + ".png"; this.seconds = counter.toString(); } else { this.imgsrc = ""; this.seconds = ""; clearInterval(timer); timer = null; router.replace({ uri: 'pages/index/training/training', params: { "key1": pv1, "key2": pv2 } }) }},
3.16 任务16:3秒倒计时结束后跳转到训练页面并传递主页面的数据
时间:2021年7月10日09:37:38
单击主页面中的按钮跳转到倒计时页面,读秒结束后,跳转到训练页面并将主页的数据传递给训练页面
倒计时页面中,将主页面传递的值作为value存放在字典中,并且通过params传递给训练页面。在训练页面中通过key,从字典中获取两个选择器的值。
梳理:
- //需要的配套格式import router from '@system.router';clickAction() { router.replace({ uri: '', params:{"":,"":} }); },//主页面 params:{"data1":picker1value,"data2":picker2value}//倒计时页面params: { "key1": pv1, "key2": pv2 }//训练页面 picker1value = this.key1; picker2value = this.key2;
3.17 任务17:呼吸训练结束后右滑查看训练报告
时间:2021年7月10日09:56:58
在多个连续的text组件中使用if-elif-else结果,以便从中选择一个text组件进行显示。在页面的最外层div组件中添加onswipe属性,从而在页面触发滑动事件时自动调用指定的自定义函数
关于if-elif-else的使用说明:因为再坚持这个text在倒计时结束以后会null,但空间并没有释放,所以需要在相同的位置进行多文本的选择,以便让空间得以充分应用
右滑:在训练页面,添加一个自定义函数,定义一个形参,在函数体中通过e.direction的值判断滑动的方向,如果等就跳转
关于onswipe属性:设置值为自定义的toReport1Page函数,这样右滑的时候触发页面的onswipe事件,从而调用自定义的toReport1Page函数。
- <div class="container" onswipe="toIndexPage">
- toIndexPage(e) { if (e.direction == 'left') { router.replace({ uri: 'pages/index/index' }); }}
3.18 任务18:将第1个训练报告页面的标题修改为压力占比
时间:2021年7月10日14:09:30
之后使用的数据都是随机生成的测试数据,其目的使其学会如何对数据进行分析和可视化展示
flex-direction样式用于指定容器所在组件的排列方向,可选值有两个:row和colum,分别表示水平方向和竖直方向。选其一为主轴,另外一个为副轴。
justify-content用于指定容器内所有组件在主轴上的对齐方式
align-items用于指定容器内所有组件在副轴上的对齐方式
书本里做了四个容器,关于着三个组件不同值的可视化案例教程,很清晰的把三个方法,十个可选值
3.19 任务19:在压力占比页面的标题下方显示压力分类的列表
时间:2021年7月10日14:35:38
联合使用list和list-item组件来展示一个列表中的多个列表项。
在list组件中使用for属性并通过动态数据绑定的方式指定要迭代的数组。在list-item组件中使用$item并通过动态数据绑定的方式指定迭代过程中的数组元素。
数据和显示需要分离
每一个列表项数据都可以用{{$item}}来表示
- <div class="state-percent"> <text class="state"> {{ $item.state }} </text> <text class="state"> {{ $item.percent }}% </text></div>
3.20 任务20:在压力分类的右边显示对应的压力占比
时间:2021年7月10日15:09:52
在onInit()中,随机生成若干个指定范围内的整数,将其作为所有压力状态的数据。根据随机生成的整数统计每种压力状态所占的百分比,并通过动态数据绑定的方式将其显示再列表中。
Math.floor(x)用于返回小于等于x的最大整数
push()函数将生成的随机数添加到stateData数组中
- onInit() { let stateData = []; for (let i = 0; i < 20; i++) { stateData.push(this.getRandomInt(1, 99)); } this.countStatePercent(stateData);},
调用countStatePercent()自定义函数,并将stateData作为实参传递给形参stateData
在自定义函数体中用四个计数器,通过for循环对stateData数组中的所有压力状态数据进行遍历,并在遍历过程中判断每个状态压力数据的范围,使用相应的计数器进行个数的统计
3.21 任务21:在每个列表项的下方显示压力占比的进度条
时间:2021年7月10日15:31:43
通过动态绑定的方式指定style属性的值
在list-item组件中添加一个progerss组件(进度条),percent属性为进度。
- <progress class="progress-bar" percent="{{$item.percent}}" style="color: {{$item.color}};"/>
3.22 任务22:添加第2个训练报告页面并响应滑动事件
时间:2021年7月11日10:36:04
就是创建页面,并通过onswipe属性,触发滑动事件自动调用指定的自定义函数
switch函数+router
- //最开始调试的代码!有错!关于direction的 toNextPage(e){ switch(e.direction){ case'left': router.replace({ uri:'pages/index/index' }); break; case'down': router.replace({ uri:'pages/index/report1/report1' }); } }}
Tips:直接点previewer可能会达不到效果,需要Debug(小甲虫)
大无语事件!大无语事件!
经过不断的控制变量调试,发现只有左右滑动才可以正常。上下滑动无动于衷,添加了生命周期,观察发现!上下滑动时,生命周期没有调用!!!!!!我就怀疑代码错了,然后仔细比对,发现没有问!没有问题!没有问题!那问题出现在哪儿了呢,排除跳转页面uri地址问题,排除了因为冒号引号的问题,排除了函数名变量名参数名不对应的问题,排除了其他页面有干扰的问题,然后我就怀疑标签direction的使用方法是不是错了。经过查验发现网上都是JS的direction标签、微信小程序的direction标签,CSS中direction的属性。对照Breathing源码发现,是因为新版的DevEco中上下左右的属性值变化了。新版的上下左右
上-top(老版本-up)
下-bottom(老版本-down)
左-left
右-right
最后说一句!!!好气好气好气!
时间:2021年7月11日12:24:15
- //调整以后的代码toNextPage(e) { switch (e.direction) { case 'left': router.replace({ uri: 'pages/index/index' }); break; case 'bottom': router.replace({ uri: 'pages/index/report1/report1' }); }
才学到的用ScreenToGif做GIF巨方便!
3.23 任务23:在第2个训练报告页面中显示除心率曲线之外的所有内容
时间:2021年7月11日20:17:45
设置有文本组件,心率通过动态数据绑定的方式将其显示在页面中,每个列表项都由一张图片和一个文本组成
- //设置的两个图片,用动态绑定加数组简单的抒写其地址<image class="icon" src="/common/images/{{ $item.iconName }}.png"/><text class="maxmin">
在data中将maxmin占位符初始化为一个字典数组,该数组包含两个字典,分表表示心率最大值和心率最小值的相关信息
- data: { maxmin: [{ iconName: 'max', mValue: 0 }, { iconName: 'min', mValue: 0 }], average: 0},
把压力页面的getRandomInt的函数复制过来,该函数用于随机生成一个介于min和max之间的整数,经过for循环执行的100次迭代,在每一次迭代中自定义函数随机生成的数经过push()的添加,最后达到hearRates数组的随机定义。
- getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min;}, onInit() { let heartRates = []; for (let i = 0; i < 100; i++) { heartRates.push(this.getRandomInt(73, 159)); } this.countMaxMinAverage(heartRates); console.log("心率页面的onInit()正在被调用"); }, countMaxMinAverage(heartRates) { this.maxmin[0].mValue = Math.max.apply(null, heartRates); this.maxmin[1].mValue = Math.min.apply(null, heartRates); let sum = 0; for (let index = 0; index < heartRates.length; index++) { sum += heartRates[index]; } this.average = Math.round(sum / heartRates.length); }
耽误一阵子时间,因为生成随机素组的时候,返回参数那里,自定义函数名字用的压力页面的自定义函数导致没有,随机数组没有正常生成
最后成功
3.24 任务24:在心率曲线页面中显示绘制的心率曲线
时间:2021年7月11日21:36:20
使用chart组件绘制心率曲线图,通过动态数据绑定的方式
制作图表需要在x、y轴上面设置参数。data中将options占位符的值初始化为一个字典,字典包含两个元素,分别用于设置x轴和y轴的参数。data中将datasets初始化为一个字典,gradient用于表示折线向下填充颜色到x轴,第二个元素是data,用于指定心率图中的数据。
特别的!对于chart线条和填充的颜色我不是很满意,我就查了开发文档,对于chart的属性进行了查询,
- options: { xAxis: {}, yAxis: { min: 0, max: 160 } }, datasets: [{ strokeColor: '#1883d5', fillColor: '#1ed1fc', gradient: true, data: [] }]
最后完成了心率页面
3.25 任务25:添加第3个训练报告页面并响应事件
时间:2021年7月11日22:15:32
就是左滑右滑的的功能实现
贯穿压力页面、心率页面、活动页面
3.26 任务26:在第3个训练报告页面中显示除活动分布图之外的所有内容
时间:2021年7月11日22:39:20
四个组件包含文本、图片的构造
定义一个名为getRandomZeraOrOne的函数,该函数用于随机生成一个整数0或1,在函数体中,Math.random()用于生成一个介于0和1之间的随机数。Math.floor(x)用于返回小于等于x的最大整数。
定义一个名为countActivityPercent的函数,其形参为activity,该函数用于技术activity中整数0和1所占百分比
3.27 任务27:在今日活动分布页面中显示绘制的今日活动分布图
时间:2021年7月11日23:16:57
与心率页面不一样的是今日活动分布页面的chart组件的type属性选择的是bar,代表是柱状图。通过stuck组件来堆叠其中的组件,从而分别绘制活动柱状图和静止柱状图。
stack:堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
3.28 任务28:添加第4个训练报告页面并响应滑动事件
时间:2021年7月12日09:42:41
添加页面并添加相应滑动,不多赘述
3.29 任务29:在第4个训练报告页面显示除压力分布图之外的所有内容
时间:2021年7月12日09:52:37
压力分布页面跟心率页面构造及其相似。四个大组件,不赘述
出现问题了!在老版本的canvas组件不能再新版本使用
canvas画布:支持手机、平板、智慧屏、智能穿戴
但不支持轻量级智能穿戴!!!Lite wearable不配
完成了!
3.30 任务30:在压力分布页面中绘制压力分布图
时间:2021年7月12日10:42:00
书中对于canvas画布组件的应用,不用用了现在,不过大致说一下书中的思路,通弄过canvas组件中的ref属性获得其对应的对象实例,并调用getContext(‘2d’)函数获得2D绘制引擎,在遍历所有压力数据的过程中调用fillRect()函数对压力分布图中的柱子逐一进行绘制
- //书中的<canvas class="canvas" ref="canvas"></canvas>
- //现在的<chart class="chart" type="bar" options="{{ options }}" datasets="{{ datasets }}"></chart>
这里需要说明一下,chart的type属性两种,bar表示的是柱状图,line表示的线形图。
相应的在生命周期onShow中,通过引用this.$refs.canvas获得report4组件的对象实例,然后调用getContext(‘2d‘)函数获得2D绘图引擎。然后通过forEach()函数进行对pressure数组中的随机压力值进行遍历,其中element表示在遍历过程中数组的当前元素。
- //书上不能用的onShow(){var context =this.$refs.canvas.getContext('2d'); let leftTopX=0; presuress.forEach(element =>{ context.fillStyle=this.getColorHexByValue(element); let leftTopY=180-element *1.8; let width=7; let height=element*1.8; context.fillRect(leftTopX,leftTopY,height,width); leftTopY +=8; });}
- //获取柱子的颜色的代码getColorHexByValue(value) { if (value >= 80 && value <= 99) { return "#ffa500"; } else if (value >= 60 && value <= 79) { return "#ffff00"; } else if (value >= 30 && value <= 59) { return "#00ffff"; } else if (value >= 1 && value <= 29) { return "#0000ff"; }},
- //用了chart那么这包含48个数组的pressure,就要定义48个字典定义柱子,for (let i = 0; i < 48; i++) { let value = pressures[i]; this.datasets[i].fillColor = this.getColorHexByValue(value); this.datasets[i].data = [value];}
用不了画布就很麻烦!就需要在data那里就定义48组数据,每组为半个小时。
不过完成了!
3.31 任务31:添加第5个训练报告页面并响应滑动事件
时间:2021年7月12日11:05:18
跟之前的页面报告页面同样的,不赘述
3.32 任务32:在第5个训练报告页面中显示除弧形和星号之外的内容
时间:2021年7月12日11:12:12
最大摄氧量页面,需要显示页面标题、最大摄氧量及其单位、摄氧量等级水平、完全跟前几个页面的构建大同小异
不过其中不一样的地方在于,正中间的两位数字,由两个图片构成,但其中有一个关系需要体现,如果小于十,第一张图if(false)(不能用show,使用show的话就是占位符,还在那个位置,我们希望他不在),唯独使用第二张图片显示最大摄氧量。
- //对应图片的hml<div class="number-container"> <image if="{{isShow}}" class="number-icon" src="/common/{{first}}.png"/> <image class="number-icon" src="/common/{{second}}.png"/></div>
- //对应图片的jsonInit() { let vo2max = this.getRandomInt(1, 70); let vo2max_str = vo2max.toString(); if (vo2max_str.length == 2) { this.first = "num-" + vo2max_str[0]; this.second = "num-" + vo2max_str[1]; } else { this.second = "num-" + vo2max_str; this.isShow = false; } this.level = this.getLevelByValue(vo2max);},
完成!
3.33 任务33:在最大摄氧量页面显示绘制的弧形
时间:2021年7月12日11:40:13
通过progress组件的type属性设置为“arc”来绘制弧形,通过stack组件来堆叠其中的子组件
progress组件percent属性设置为百分之50,添加style属性用来设置进入条样式。start-angle设置为220(起始角度)。
- <progress class="progress" type="arc" percent="50" style="color : #ff0000; start-angle : 220;">
弧度百分之50的效果图
接下来是七彩阳光环节,哈哈哈,就是七个颜色弧形
3.34 任务34:在最大摄氧量界面的对应弧形和角度上面显示星号
时间:2021年7月12日12:06:26
嗨,还是使用的canvas,其思路就是X-Y轴的绘制,然后添加“*”的文本
不过呢现在就用的是
- //现在就比较直接添加组件,然后在js里直接设置对应位置<div class="pointer"> <text class="pointer-txt" style="margin-top: {{y}};margin-left: {{x}};"> * </text></div>
- //css.pointer{ width: 454px; height: 454px; background-color: transparent;}.pointer-txt{ font-size: 38px; color: yellow;}
- //在js的onInit的里面直接动态绑定x、y的值let angle = -230 + vo2max * (280 / 70);this.x = Math.round(218 + 193 * Math.cos(angle * Math.PI / 180));this.y = Math.round(218 + 193 * Math.sin(angle * Math.PI / 180));
完成!
3.35 任务35:添加学习交流联系方式页面并响应滑动事件
时间:2021年7月12日12:15:04
新建一个contact页面,添加相应的文本和router.replace的滑动跳转,不赘述,要完结了!要学完了!冲冲冲!
3.36 任务36:在学习交流联系方式页面中显示二维码并完成项目收尾
时间:2021年7月12日12:22:15
使用image组件显示二维码,就是一个收尾工作喽!冲冲冲!
完结撒花的时候因为图片的比例问题,又在华为开发文档里面去学习了一下image组件哈哈哈。
最后选的是自己以前剑网三丐帮的一张图片!
潜龙勿用!自强不息!
后面收尾有一个简单的提示语的添加(text组件)
书上的完结!
六、对项目的一些调整和感想
(一)点击重新开始的按钮太大了,下面的框框都兜不住了
时间:2021年7月12日12:59:50
对训练页面的btn按钮的进行调整(css)
- .btn { width: 280px; height: 50px; font-size: 38px; background-color: aquamarine; border-color: aquamarine; margin-top: 15px;}
(三)一点感想
时间:2021年7月12日13:08:29
首先我很感谢《鸿蒙应用开发实战》这一本书!当然最应该感谢的是张荣超老师,他写此书是开拓性的行为,虽然现在DevEco的版本迭代很快,书里的部分内容需要调整,但试错与改BUG本来就是一名程序猿需要去干的,原封不动的照抄代码,反而效果可能没有那么美丽!还有就是在学习的过程中我还加入了张荣超老师的粉丝企业微信,然后在里面得到了老师耐心的讲解!!!真的太佩服他了!更甚,张荣超老师在51CTO社区发的学习鸿蒙的文章也很有代表性!最近发的【张荣超老师】鸿蒙卡片开发超细致总结 ,也特别特别的详细!ps:接近凌晨十二点张老师也回复了!!!!
总结一下这本书和这段时间的学习:没有案例没有项目的学习,是支撑不起实际开发的,选择这本书就是为了可以快速的上手,在简单项目中学习DevEco的相关设置、一些快捷键的使用;DevEco中JavaScript的Lite wearable的开发,熟悉轻量级智能手表的API,
在这里就这个项目还有可能完善的地方就是,使用全部的轻量级手表专属API中,
《鸿蒙应用开发实战》使用的组件:
容器组件:div(基础容器)、list(图片文本的列表项容器)、list-item(< list >的子组件,用来展示具体的item)、stack(叠堆容器)、swiper(滑动容器)
基础组价:chart(线性图、柱状图)、image(图片)、image-annimator(图片帧动画播放器)、input(交互组件)、picker-view(嵌入页面的滑动选择器)、progress(进度条,用于显示内容加载或操作处理进度)、text(文本,用于呈现一段信息)
《鸿蒙应用开发实战》未使用的组件:
marquee:跑马灯组件,用于展示一段单行滚动的文字
qecode:生成并显示二维码。
silder:滑动条组件,用来快速调节设置值,如音量、亮度等
switch:开关选择器,通过开关,开启或关闭某个功能》
还有一些具体的注意事项我把他放到了第二点,尤其是DevEco新老版本不一样的地方需要诸君多多注意!
完结撒花 诸君共勉!学习继续 强国有我!
附上自己敲的代码
注:该文都是自己学习过程的笔记,侵删。