【项目】百度计算器仿写
Dandelion 6/12/2022 project
# 准备工作
- 需求描述
- 百度计算器仿写
- 其他计算参照:Click here (opens new window)
- 用户体验
- 技术选型
- 开发规范
- 主要功能
- 计算器实现
- 响应式设计,移动端适配
- 网络延迟响应,懒加载,首屏加载,骨架屏
- 夜间模式,系统适配
# 进度
- 框架搭建(6.13-)
- div+css
- tailwindi
- antd
# Question List
- % px rem em vw vh 如何适配页面?
- Screen Reader + Keyboard Shortcut
- PC 端常见媒体查询尺寸:1024 1280 1366 1440 1680 1920
- 前端自适应解决方案:媒体查询,百分比,rem,vw/vh
- 为啥设置 z-index 不起效果?没有设置 position
# TailWind CSS 的使用
- 移动优先,先 sm,再 md,以此类推
- @apply 复用类组件
- @layer components:提取组件
- 计算器布局:应进行区域划分,如所有数字按钮是一个整体,不能随响应式布局的处理而被打乱。(flex 布局不易实现,换成 grid 布局)
- 计算器逻辑:(1)粗暴式:eval();(2)其他:状态机,如XState (opens new window)。
- 深色模式的使用:(1)tailwind.config.js 中设置
darkMode: 'class'
;(2)监听模式切换事件,document.documentElement.classList.add('dark')/remove('dark')
。
# Vue3 的使用
- 选项式/组合式(setup 函数)
- props 传递
- 父传子:父组件 : 绑定参数名,子组件定义对应的 props 名称。
- 子传父:父组件定义 xxx 函数,并@绑定函数,子组件定义 emit,并在触发某个事件时调用
emit('xxx', { data: ... });
将数据传入父组件。
- state 管理
- 路由管理
# XState 状态机的使用
- 绘制状态转化图:https://stately.ai/registry/editor/share/311f1dce-6fee-4619-88b8-e6d5f2542d39
- counterMachine 定义状态转换,可由状态图转换而来,其中包括全局状态变量的存储,即 result 和 inputStr;
- useCounterMachine = interpret(counterMachine).onTransition(state => console.log(state.value, state.context)).start();
- 页面的点击事件触发状态的转换:
useCounterMachine.send({ type: 'OPER' , value: '+' })
- 其他方式:Vue 和 xstate (opens new window)
# Vite Plugin PWA 的使用
- 考虑到大多数情况下计算器在离线时也应该可以正常使用,因此,想设计成类似桌面应用的软件供用户使用。
- PWA,Progressive Web App,渐进式网页应用程序,可以加载离线数据。三个显著特点:
- Reliable:不依赖网络状态,可以随时加载出应用。
- Fast:可以立刻加载出网页。
- Engaging:PWA 可以添加在用户主屏幕上,不用从应用商店进行下载。通过网络应用程序 Manifest 文件提供类似于 APP 的使用体验,并且还能推送通知。
- 基于 service worker 技术实现:
- 基于 web worker,增加了离线缓存的能力。
- 本质上充当了浏览器和服务器之间的代理角色,如果可以直接使用缓存就返回缓存中的数据,否则将请求转给服务器。
- 可以让开发者自己控制管理缓存的内容以及版本。
- vite-plugin-pwa,vite 的一个官方插件,通过简单的配置将你的 vite 项目变成 pwa 应用。
- 关于
service worker
的实现直接采用的谷歌开源库workbox
,帮开发者对缓存做了大量的逻辑代码处理,也支持多种不同的缓存策略,并且也封装好了 sw.js 文件的更新策略。 workbox
的缓存策略- Stale-While-Revalidate:首先通过 service worker 匹配缓存,并且每次仍然还是会 fetch 一次接口,并将请求的结果更新缓存。
- Cache First:优先访问缓存,匹配不到才会重新 fetch 并缓存。
- Network First:网络请求超时便会返回缓存。
- Network Only:只用 fetch 接口数据。
- Cache Only:只用缓存。
- 关于
- 开发者工具:Application -> Manifest(查看相关配置)
- 参考
# 无障碍优化(WAI-ARIA,Web Accessibility Initiative - Accessible Rich Internet Applications)
- 目标:解决如何使得元素属性被正确识别,如何使得元素内容被清晰准确地朗读,如何排除干扰元素等问题。
- 开发细则
- 尽量避免使用会影响到 DOM 视觉顺序的样式(如
flex-direction: row-reverse;
),若无法避免,需要手动设置 tabIndex 属性,告知读屏软件正确的内容顺序; - 为非文本元素提供文本说明:如
<img alt="文本说明" />
,<video title='文本说明'>
等。 - 使用语义化的元素:
- 尽量使用语义化标签(会隐式加上特定的 role 属性),如
header/footer/nav/button/a
等; - role 属性:若出于其他考虑,使用了非对应语义的标签,可通过添加
role = 'button/link/...'
来进行语义的声明,影响朗读时的修饰词; - disabled 属性:禁用状态(对于没有 disabled 属性的标签,可以使用 aria-disabled 属性达到同样的效果);
- aria 标签属性:向不存在原生语义的元素添加语义,如
aria-label = '额外的描述'
、aria-live='true'
等;learn more (opens new window) - 隐藏屏幕外的元素:使用
display: none
或者visibility: hidden
隐藏这类元素(如浮动出现的 alert 和 banner 等),若不便添加样式,则可添加aria-hidden = 'true'
的属性。
- 尽量使用语义化标签(会隐式加上特定的 role 属性),如
- 使用 Tab 按键进行聚焦
- tabindex 属性:与键盘访问行为息息相关:负数,0,正整数。
- :focus 的样式:轮廓由 outline 决定,不是 border。
- 方向键按下事件的监听:将所有按钮元素存进一个二维数组,然后取页面聚焦元素对应的行号和列号,再据此判断方向键按下时聚焦元素的走向。
- JS 获取屏幕、浏览器、页面的高度以及宽度 (opens new window)
- autofocus 和 accesskey(快捷键) 属性的设置。
- 注意:当监听事件(如 keydown)并不需要绑定到页面上某个特定元素时,可以直接绑定到 document 上,从而避免冗余代码。
- 尽量避免使用会影响到 DOM 视觉顺序的样式(如
- 参考
- Web 可访问性与无障碍最佳实践 (opens new window)
- Web Content Accessibility Guidelines (WCAG) 2.1 (opens new window)
- 键盘导航的 JavaScript 组件 (opens new window)
- 使用 tabindex 控制焦点 (opens new window)
- 键盘:keydown 和 keyup (opens new window)
- 聚焦事件:focus/blur (opens new window)
- Tab 键、方向键切换页面控件焦点 (opens new window)
- 键盘事件无障碍使用总结 (opens new window)
- 使用 PWA 将 web 应用安装到桌面 (opens new window)
# 功能实现
- 计算规则:只考虑简单的二则运算(+-*/)
- 输入数字:
- 只输入多次零,显示为一个零,不更新显示(默认显示为零)
- 输入多次零,紧接着输入非零数字,直接显示非零数字
- 连续输入多次小数点,只保留一个小数点
- 在输入已经是小数的前提下,再输入小数点,将忽略该小数点
- 输入运算符:
- 连续输入多个运算符,只保留最终输入的运算符
- 其他....
- 输入数字:
- 实现一个离线版本,怎么进行更新?
- 实现无障碍模式,使用键盘发出声音,有助于为特殊群体提供更好的服务。