这周做两个移动端的页面,终于接触了移动端,第一个是要内嵌在游戏里的 webview 页面,一个是放在 app 里的。
两个页面使用的都是 flexible.js ,flexible 适配方案的思路是模拟 vw ,将页面分成10份(vw是分100份),计算网页元素(比如一个按钮)在一张设计稿里所占的比例。将 1rem 设为 1/10 的设备宽度。
按钮宽度 = 所占设计稿比例 * 1份设计稿宽度
比如有设计稿 750px 宽, 其中有按钮150px,则按钮占页面比例是 20% ,一台设备宽度为 320px 的手机,分100份每份 3.2px ,则该按钮在手机里显示的宽度就是64px;原理是这样,但是因为 flexible 是将页面分成10份,所以在 sass 中的换算公式其实是:
$rem = 75px;
@function px2rem($px) {
@return $px / $rem * 1rem;
}
这样每个网页元素都能在页面中按比例缩放。
做游戏内嵌页面的时候踩到的一个坑是怀疑用了旧版本的 flexible,在计算 root font-size 的时候如果大于 54px,会将 root font-size 限制在 54px,看到有人给的解释是,因为大于 54px 会被认为该设备非移动设备,而为了照顾页面在 PC 端的效果,才将 root font-size 限制在 54px 。但是我看现在版本的 flexible 已经去掉了这个判断,原因估计是:既然是移动端的页面那就没必要再对 PC 端做处理吧。
而我的页面由于是横屏的,需求方给的尺寸是 828 * 540,导致计算出来的结果一直是 54px ,这让我在计算网页元素尺寸的时候老是不能“所见即所得”,彼时我对 flexible 的运作原理还不清楚,还是靠师兄发现的这个坑。最后把这段对 54px的限制去掉, px2rem中的 $rem 改成设计稿的 1/10,页面就正常了。
发现移动端如果不是因为一些细节的兼容性问题的话,做页面布局其实实现起来会比 PC端容易得多,因为页面元素少,布局简单。而且可以使用 CSS3 的特性,后续会做到一个装盘动画就可以用 CSS3 来实现。
背景图片的适配
一些按钮会用到背景图片,要加一个 background-size: cover
让背景图片完全显示在按钮中,因为一个按钮放在移动端页面大小会小于图片的大小,比如按钮在网页里只有 64 * 39,但是背景图有 128 * 78,这个时候就需要 background-size: cover
让背景图按比例缩小后完全显示出来。
flex布局
移动端是可以使用 flex 布局的,但是现在 flex 最常用到的属性只有三个:flex
,align-items
,justify-content
,感觉没发挥出 flex 的什么威力。align-items
用在决定 item 在副轴上的排列方式,justify-content
用来决定 item 在主轴上的排列方式。
当在一个 flex 容器中只有一个 item 时,在容器使用 margin: auto
,可以实现 item 的垂直水平居中。
flex 容器里的 item ,float
, clear
,vertical-align
都会失效。
router的使用
做游戏内嵌页面的时候第一次用到了 react-router。
router 用一个 <Route path="" component="">
标签当作一个“占位”,component
就是跳转到path
时会使用的组件。
router 支持模糊匹配,例如path="classify/:name"
,后面的 name 就是一个可以自由决定的字符串,可以在页面跳转后通过match.params.name
获取到,就可以利用这个参数搞事情。
都知道利用 URL 可以传递一些参数,但是如果要传递的数据太大,怎么办呢,可以通过一个location对象
let location = {
pathname: '/path',
state: obj
}
this.props.history.push(location)
将要传递的对象放到location.state
中,再使用history.push()
做跳转,将数据带到下一个页面。history
是默认每个组件的props都有的一个属性,只要你通过高阶组件withRouter
将根组件<APP>
传入withRouter
,就可以在每个组件的props上取到 router 的 history, match, location
。
感觉到状态管理的必要性
做 PC端页面的时候,弹窗都经过封装可以直接调用, 移动端的弹窗需要自己封装,弹窗的开启关闭也需要自己去管理,还有一些需要路由跳转的情况下,数据需要保留在根部组件,每次更新都要重新setState
,setState
得不好还会导致覆盖前面的state
,就会导致想要获取prevState
的时候发现prevState
跟当前的state
一样。所以是时候上手一波状态管理了。
antd-mobile 的使用
虽说弹窗要自己写,但不需要细致到蒙层,关闭效果也要自己实现,因为有 antd-mobile 的存在。提供了高度的可定制,一个弹窗完全空白让你自己定制,还支持多种弹窗方式,点击蒙层窗口是否关闭等选项。
滚动元素到当前视窗
滚动一直是比较蛋疼的问题,因为关于滚动,高度的属性太多,导致选择用什么属性去计算滚动距离总是昏了头,上周日搞到12点的问题,还是被师兄半小时解决了问题T T,所以还是要多多静下心来想一想怎么解决问题比较重要。
要实现的是像聊天一样,发出一条新消息后,新消息要显示在当前视窗,现在解决思路很清晰,首先,滚动的是容器,而要显示出来的 消息div 在容器的底部,要使 消息div 出现在当前视窗,就要获取 消息div 到 document的距离,再加上容器已经滚动上去的距离,就能使 消息div 出现在当前视窗。但是这种实现还有点瑕疵,就是容器与 document 之间还有一定距离,减去这段距离才能让 消息div 完美出现在当前视窗。
总结几个经常用到的滚动和高度的属性:
- 在jquery中,用 scrollTop() 获取和设置元素滚动的距离;
- 在jquery中,offset().top 获取的是元素到 document 的距离;
在原生中,使用 offsetTop 获取元素到 document 的距离;getBoundingClientRect()也是用于获取元素到 document 的距离
- 在 jquery中,position().top 获取的是元素相对父元素的距离,
关于宽度和高度的取值
- clientHeight = padding + width;
- getBoundingClientRect().width = offsetWidth = padding + border + width + 滚动条;