h5开发总结
做了两个月的创意h5,其中遇到了一些坑与兼容适配方面的问题,做个记录总结,基于vue开发
1. 布局
1.1 元素的长宽
通常用rem来设置宽高,rem: 相对于根元素html的字体大小的单位
把标准@x2设计稿750宽的根元素的字体大小设为50px,就可以直接按设计稿的长宽/100来直接定义元素的宽高了
1 | html { font-size: calc(100vw / 15);} |
1.2 底部菜单栏的高度兼容
这个问题包括了浏览器端底部菜单,还有ios端的微信第一次进入,会有底部状态栏
qq浏览器把底部菜单栏,当作了body的一部分,相当于是一个固定在底部的菜单栏,但是层级是最高的,所以当使用绝对定位,bottom:0
放元素在底部的时候,元素是会被覆盖掉的。或者高度设为100%或者100vh底下的元素也会被覆盖掉
纠正最大长度
通过global变量监听获取当前视口的高度window.innerHeight
。并随时更新。然后在在CSS中自定义变量--vh
。动态改变它的高度,第一次知道setProperty
可以让js设置css的变量,js与css通信
1 | // 监听它的高度变化,写在项目初始化 |
1.3 需要适配到的宽高比
短屏适配需要做到9/13的宽高比例才能完全在浏览器有底部栏出现的情况下显示正常,最好要向设计师提前说明不要将元素撑的太满,做一部分的长度适应
不然设计师以iphonex为设计原型,又不留白,页面实现就会超出可视区域
1 | // 屏幕宽高比9比13 |
1.4 滚动条问题
一般设置绝对定位元素会超出屏幕,这时会出现滚动条
1 | // 在每个页面夫元素设置可视宽高,然后超出部分隐藏 |
如果页面只在一屏展示,禁止可上下滑动,页面体验效果更好
1 | document.body.addEventListener('touchmove', function (e) { |
手指按住屏幕下拉,屏幕顶部会多出一块白色区域。用了以上的禁止touchmove
事件就不会出现下滑效果,体验更像原生程序
2. 动画
2.1 序列帧动画的实现
为什么不用GIF图
- gif 支持颜色少(最大256色)、Alpha 透明度支持差,图像锯齿毛边比较严重;
- 不能直接控制开始、停止、动画时间,灵活性差;
- gif 会引起页面周期性的绘画,性能较差。
实现
原理:把雪碧图的第一帧设为初始背景,短边设为显示宽高,通过CSS3 animation动画位移雪碧图的 background-position
,模拟动画效果
1 | .sprite { |
animation
动画:
animation-name
:动画keyframes 名称,可以用百分比表示时间节点,也可以用from-to,表示0%-100%animation-fill-mode: both;
应用目标时立即应用第一个关键帧中定义的值,并且保留由执行期间遇到的最后一个关键帧计算值animation-iteration-count
动画运行的次数 infinite 无限循环animation-timing-function: steps();
steps 函数指定了一个阶跃函数,它接受两个参数。
第一个参数接受一个整数值,表示两个关键帧之间分几步完成。
第二个参数有两个值< start > or < end >。默认值为< end > 。
step-start 等同于 step(1, start)。step-end 等同于 step(1, end)。
steps(7)就是关键帧分7步跳跃。把单个png图的宽或高*7设为最终背景移动位置
2.2 解决动画帧抖动问题
帧动画在部分机型出现了抖动或着位移的问题,发现是rem转为px存在小数点,除不尽误差的问题,误差就会导致有些机型有抖动或者位移现象。
既然我们通常是根据屏幕的尺寸,计算并设置根元素的font-size,从而影响rem的基准值。那不同的尺寸之间肯定是没有一个公约数的,也就是说我们没办法设定一个基准值来保证不同的屏幕尺寸下,rem值在换算成px值的时候是整数。
当320px的屏幕基准像素为12px时,iphone8(375px)下
html
的font-size 就是14.0625px,iphone8p下font-size就是15.525px。
浏览器在计算像素精度时,并不是直接全部取整或者取余的,这点其实你稍微想想一下就能得到结论。那我们上文这样在109rem的宽度下取16帧的时候,自然也就会出现多1px或者少1px的误差。这也就导致了我们逐帧动画出现了抖动!
解决:
- 可以使用
transform: scale()
将其放大,然后rem除余成px的时候误差会减小 - 使用svg设置外层尺寸(rem),再使用实际的大小设置内容的尺寸(px),我们保留rem自适应屏幕宽度特性的同时,也确保内部内容的大小计算不会出现精度问题(因为设定的都是整数的px)
1 | <svg viewBox="0, 0, 536, 652" class="tiger-tail"> |
1 | // 外层svg包rem |
Tips:
建议不要使用太长或者太宽的雪碧图,使用矩形的雪碧图,cdn存图的时候会把过长的图片给裁剪掉
ios下帧率最好不要太高,不然会导致不断刷新的问题,每秒50帧的时候会无限刷新,设置25帧就不会出现这个问题了
推荐一个帧动画生成工具https://gka.js.org/#/
2.3 CSS 星轨运动实现
因为星星轨迹是椭圆且有角度的,而且是椭圆轨迹
之前看到篇文章 分层动画在CSS中沿弯曲路径移动,所以感觉可以通过X轴加上Y轴的分层动画融合,加上速度不同步,实现对角线曲线运动
1 | .dot { |
要实现它的曲率主要靠,速度不同步,比如y轴速度大于x轴,运动曲线就会是一个上拱的抛物线
调节特定的曲率 ease-in,out,linear就远远不够了,需要用到赛贝尔曲线来调节animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
可是即使有可视化的曲线调节,但是结合xy轴相乘就非常难控制了,与线条轨迹不能重合。所以只能另谋出路了
正圆的旋转实现
使用传统的圆周转,实现绕圈旋转的animation
,一个周期旋转一周。
1 | @keyframes spin { |
可是物体在绕圆形路径旋转时,发现自身也颠倒了
解决方法:时利用两个元素在向不同方向旋转时旋转角度互相抵消的原理,实现图像沿环形路径旋转同时保持自身角度的不变。外层旋转 ,里面物体反旋转抵消被旋转效果,就是有环形轨迹运动物体不颠倒的效果了,然而这样子就需要一个相反的动画,使用animation-direction: reverse;
可以得到一个反向原动画,不需要创建第二个动画
再优化:每个transform-origin
可以模拟两次translate()
。
1 | // 以200px,300px 为圆心旋转30度 |
通过translate的抵消,出来了一串简介的代码:
1 | @keyframes spin{ |
学习的文章:https://www.w3cplus.com/css3/css-secrets/animation-along-a-circular-path.html
正圆实现了,如何实现椭圆呢,之前找的分层动画也没有白费,在元素里加一个y轴的上下移动,融合入正圆,就可以画出椭圆效果来
再在大div里加入一个角度,在animation里再旋转棱形块,旋转了运动轨迹,行星又是水平的效果,达到设计图的要求
2.4 如何实现3d开门效果
实现方法:两个div叠加,外层div进行旋转
1 | @keyframes flip-to-left { |
但是这样只是一个平面的效果,只能看到一个窄的和宽的矩形,看不到立体的效果。然后找到一个属性添加景深transform-perspective:1000px
,有了立体的感觉
又发现一个问题:虽然有深度,当还是平视效果,与设计图不符合
需要有一个摄像机视角在这个门的上方,从上往下看的视角,打开的门类似于平行四边形才能与设计意图相符合
找到一个冷门属性,transform-style: preserve-3d
元素的子元素们是放置在 3D 空间中
transform: rotateX(15deg)
就有了俯视的视角 ,还可以实现这种立体的效果
3. 业务通用组件
3.1 背景音乐自动播放多端兼容
音频组件适应各端,ios ,安卓,微信,qq
iOS 端 safari 浏览器或者部分安卓手机的浏览器不支持 autoplay 属性。
解决方法:还是引导用户手动触发播放操作。
比如绑定 touchstart 事件进行 audio.play() 操作
1 | touchInteract () { |
3.2 敏感数字过滤
敏感数据存放在Set集合里面,如果命中,就加一显示,set时间复杂度O(1),比数组查找每次遍历O(n)性能更优
通过filter管道过滤likeRankData.like | filterSensitive
,实现敏感数字自动加一显示
1 | const sensitiveSet = new Set([6489, 8964, 53589, 89535, 198964, 641989, 1989535, 5351989]); |
3.3 组件间的过渡
所有题目的流程过渡都有渐入渐出的一个效果,为了避免每个组件都写重复的场景过渡,打算自己写一个方法,结果在vue文档找到了一个官方的过渡方法,:is="组件名"
,动态写入组件名,监听到data中的‘quesStep’改变后就会执行过渡转到下一个组件
1 | <transition name="fade" mode="out-in"> |
所有场景的延迟显示细节也都可以使用transition过渡,适合流程类的需要渐入渐出场景页面
4. 总结复盘
- 项目开始之前,确定哪些组件是可复用的,项目复用级,全局复用级 eg: 全局的背景音乐,动效等
- 可以把 vue 拆开 ,避免一个文件过大 难维护
- 有些布局,老操作系统不兼容,写之前,多考虑兼容,不然测试出来不兼容,再修改麻烦
- 对于一些点击响应需要低延迟的使用
touchstart
,click
事件可能会有延迟 - 项目完成计划在前一周就给设计体验,测试提测,避免在上线前来不及修改
- 列bug优先级,先解决逻辑体验上bug,再解决样式小问题
- 解决bug方面的能力有待加强,怎么解决:
- 列bug优先级,先解决逻辑体验上bug,在解决样式小问题
- 精准定位,是否可复现,找到bug原型机
- 打断点看哪里数据出错了,是什么类型的问题
- 移动端不推荐用img标签,长按会触发保存,所以要创一个节点,然后使用背景嵌入图片background
- 不要把所有页面的图片加载都放在最前面的loading页,等待时间长用户会流失,在每一页动态调用下一页的图片的动态预加载函数
- 使用replace跳转路由,push路由会导致底部出现底部状态栏