成品网站可以在这里查看(请使用手机)
0.前言
10.4晚上,写完高数线代作业终于空下来了,出了趟门后准备开始写助手的任务。
第一项搭建个人博客的任务暑假刚好做完,省事了。我选择第二项制作天气卡片的任务。因为要求把开发过程做一篇记录发表,于是就有了这篇文章。
1.数据源
拿到手的时候任务介绍里指路了可以使用高德或者彩云的天气api,但是恰逢国庆,彩云开放平台审核放假了,一直是Pending Review的状态,于是我转向高德。
高德的api很简单,一下子就弄懂,可惜它提供的更多是地图方面的服务,天气数据实在太有限了,不足以完成进阶任务。找了一晚上,选定了和风天气API,对于个人开发者的优待完全满足了我的需求。
认证个人开发者有也非常快,应该是采用了AI审核,我凌晨发出申请,半分钟后就通过了,太感动了。
可靠的数据源到手,着手开始制作。
2.构思
- 任务建议使用原生js实现,且没有指定平台。鉴于助手在手机端更常用,而且时间很有限不足以完成响应式布局,我决定开发手机页面,这样可供参考的软件也会很多。
- 网络请求: 决定使用axios,因我没用过,想试试。
- 天气图标: 和风天气设计了一套开源的和风天气图标,仓库地址在这。
不过它只设计了天气现象相关图标,缺少诸如大气压、紫外线、日出、能见度等图标,但是先凑活着用吧。 - 图标展示: 推荐的Charts.js文档实在难看懂,网上搜索不到几篇教程。最后选择了Apache基金会的ECharts.js,不仅有中文文档,网上能搜到的教程也多得多。不过全功能的包体有点大,等以后可以研究一下按需引入。
- 页面布局:我结合了手头的华为天气和数据提供商自己的一个S和风天气app。
3.动手
3.0 IDE选择
以前开发我基本就用DW或者vsc + 浏览器内建的样式编辑器,这次想尝试一下JetBrians WebStorm。
一是听说它的代码补全很强,二是杭电学生认证后有正版的全家桶可以白嫖。
3.1 简易搭建一个本地缓存
- 修改CSS的时候如果实时预览,每次修改保存都要重载页面,向api获取数据,不仅耗时而且浪费很多的使用次数,于是用Python在本地创建了一个服务器,作用就是读取预先保存的json再返回。测试的时候只要用本地的api就好了,反正不需要最新数据。
需要注意的是,即使json和py文件都是utf8编码,也应该指定一下open函数的打开编码,比如在我这就默认用gbk打开了,显示“’gbk’ codec can’t decode byte 0xb4 in position 179: illegal multibyte sequence”。
解决方案:在open()函数里传递encoding=’utf-8’的参数,例如:
1
with open('now.json',encoding='utf-8') as f:
- 由于WebStorm的本地调试服务器和Python的临时数据服务器不在一个端口上,请求会因为跨域被阻止。为了测试需要,就要设置响应头。
在Sanic中,中间件(Middleware)功能可以在请求到达路由的前后处理数据,以此来实现用户自定义的全局功能。在这里,因为需要进一步处理相应,所以我们将中间件绑定到“response”上。这里使用装饰器的形式实现。
1 | @app.middleware('response') |
然后,我们自定义一个函数设置服务器允许任何域访问资源(临时调试用,在生产环境请严格指定域来避免安全风险)。
1 | async def fkCORS(request, response): |
现在整个中间件看起来是这样的
1 | @app.middleware('response') |
MDN上的“Access-Control-Allow-Origin”
Sanic 入门:中间件(Middleware)
- Sanic的服务器会绑定主机名称,如果我们的局域网ip为10.66.233.77,但设置服务器host为localhost,port为8090,则不能通过10.66.233.77:8090访问到网站,只会显示拒绝连接。
如果想要用局域网设备访问,比如使用手机真机调试,我们应将host设置为局域网ip地址来规避这个问题。1
2if __name__ == '__main__':
app.run(host='10.66.233.77',port=8090,debug=True)
注意,如果你的局域网ip地址不是固定的,记得手动在变更后修改。
3.2 使用css计算器生成线性背景渐变图
制作过程中为了顺畅衔接地图和天气卡片,需要给卡片所在容器设置一个由透明到渐变再到完全纯色的背景。同时卡片本身就需要一个渐变色。
这里就用到了“linear-gradient()” 这个函数。
linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片。
注意,因为是图片,所以只能被用于图片可以被使用的地方,而并不适用于background-color等属性
卡片的渐变比较简单,从只需要从左下角颜色渐变到右上的颜色即可:
1 | #overviewCard{ |
在背景用例中,我需要一部分纯透明区域,一部分渐变区域,一部分纯色区域。这些区域的范围是可以手动指定的,像这样:
1 | #overviewContainer{ |
实际效果如下:
3.3 使用三目运算符动态分配类名
在24小时预报和7天预报中,为了将相邻两个容器区分开来增加可读性,需要在生成html的时候动态指配两种class
刚好上周的C语言课程学到了三目运算符,可以迁移到js上来(在js里似乎叫三元运算符或者条件运算符)。
因为具体用法相同,在C语言的课程上讲过,就不再做解释了,相关代码如下
1 | let html = ""; |
实际效果如下:
3.4 使用css var()函数实现暗黑主题
不管是什么主题,整个网站都会遵循一定的配色标准,简单来说就是分门别类,不同作用的元素对应了不同的颜色。
当我们启用暗黑模式的时候,同一作用的元素需要切换颜色。
如何不用写两套css就能实现这种效果呢?我们可以用var()函数配合相应变量替代掉所有颜色区域。
相应的颜色可以定义在根元素节点上,比如<html>标签中,比如
1 | :root{ |
其中:root 选择器匹配文档根元素。在网页中,根元素始终是<html>元素。
然后在需要切换颜色的地方,都应该显式指定相应的颜色变量:
1 | #overviewCard{ |
现在我们看到,默认情况下浏览器使用:root定义的颜色组:
当我们给<html>添加类”dark”的时候,dark颜色组覆写了root颜色组的设置,<html>里的元素都会继承dark的变量设定:
这样就能实现颜色切换了。
3.5 动态切换图表的配色
很遗憾,解决了基本元素的配色问题,我们还需要单独解决图表配色。因为图表的颜色设定实际上是写在js的json中传递给函数的。
相关设置可以在ECharts的配置项手册中很详尽地看到,这里不再赘述
因为图标在创建后支持动态更改设定,所以我们使用darkCharts()和lightCharts()两个函数交替切换图表样式,缺省设置会保留之前的,但是要求格式完全一致
下面是部分实现代码,可以看到非常难以阅读(这里我使用变量来代替所有相同部分以便后期快速更改):
1 | function darkCharts(){ |
吐槽:在新版的更新日志里已经不建议我使用textBorderColor和textBorderWidth两个属性,然而它并没有提供合适的替代属性,所以还是只能用着。害得我找了好久更优解。
3.6 模拟$(document).ready()与初始填充内容
没时间做鱼骨屏了,而且提到的方便工具都在vue或者react体系下,我也用不了。
于是我准备直接在页面加载时初始化一系列空数据,有总比没有强。然后在获取到具体数据以后或替换或更新。
这里我发现,原生的js并没有提供像jQuery库一样方便的现成函数$(document).ready()。
但是我们可以通过判断document.readyState来自己造一个轮子
当document.readyState变为interactive(可交互)时,就代表html文档已经解析完成,但是诸如图像,样式表和框架之类的子资源仍在加载。实际上这相当于$(document).ready()的状态。
当该属性值发生变化时,会在 document 对象上触发 readystatechange 事件,通过监听这个事件来运行回调函数,我们就可以模拟出一样的效果
代码如下:
1 | document.onreadystatechange = function () { |
3.7 localStorage储存偏好和原生实现类的增删改
这对我而言完全是完全是新东西了,以前只接触cookie。
localStorage是持久化的本地存储,除非是通过js删除,或者清除浏览器缓存,否则数据是永远不会过期的。
而cookie是用于客户端和服务端间的信息传递,每次请求都会被附带在请求头中,因此不适宜储存大量数据或者用户个人偏好。
在这里我用localStorage储存了用户上次使用的主题偏好,可以在每次刷新时自动应用,防止闪瞎。
localStorage的增删改函数是原样从Sukka的博文你好黑暗,我的老朋友 —— 为网站添加用户友好的深色模式支持中抄来和简化的,我就不放代码了。
在简化过程中准备直接给<html>标签设置颜色组属性,结果,很遗憾发现原生js没有现成的封装,于是从网上又抄了一个。
稍微改了下,因为WebStorm疯狂说我代码不规范,变量乱声明。
技术细节到这里就结束了
4.后记
终于写到后记了,写个博文用了我4个小时,累死了(所以博客才万年不更新的)。
- 这次因为时间仓促,额外发挥的部分要求,比如响应式页面、骨架屏、toast用户提示、webpack打包等没有实现。
- 整个网页是国庆花了整两天搓出来的,期间学习了ECharts、axios、localStorage、css函数等各种新知识。
- 我没有预料到新知识的学习成本还是很高的,耗时非常严重。然后在一开始寻找合适api,选择合适图表库的时候走了很长的弯路。
- 这次是我第一次写出一整个兼具美观和功能的网页,还是很有成就感的(但是真的累,两天速成不可取)
- 美中不足的是高德地图的JS API竟然没有提供夜间模式的地图,结果开了夜间模式首屏还是瞎眼了,唉
- 这次是我第一次用原生js来实现一系列功能,感谢You-Dont-Need-jQuery的指导,让我看到了一系列jQuery封装后各种功能本来的样子。有些地方,原生js也能一样简洁!
最后,如果博文有错误或者错字的地方,欢迎指出(其实大概仅限于我认识的人,因为博客没有评论系统)
你可以发送邮件到asak&irain.cc(请把&换成@)
很荣幸能得到你的耐心阅读!