《微信小程序七日谈》- 第二天:你可能要抛弃原来的响应式开发思维

摘要:
本文以作者在为applet开发响应UI时遇到的一些问题为例。rem重新定义的前端工程师非常熟悉rem。rem是一个基于html元素字体大小的尺寸测量单位。Rem便于开发人员整体管理响应UI的大小。1rem=(750/20)rpx中750的值是wxss将设备屏幕的宽度统一定义为750rpx,但wxss的rem与引导的网格系统不同。

《微信小程序七日谈》系列文章:

  1. 第一天:人生若只如初见
  2. 第二天:你可能要抛弃原来的响应式开发思维
  3. 第三天:玩转Page组件的生命周期
  4. 第四天:页面路径最多五层?导航可以这么玩
  5. 第五天:你可能要在登录功能上花费大力气
  6. 第六天:小程序devtool隐藏的秘密;
  7. 第七天:不要捡了芝麻丢了西瓜

本系列的文章并非初学教程,而是笔者在具体开发过程中遇到的问题以及部分解决方案。

上篇文章 第一天:人生若只如初见简单记录了笔者初步上手开发微信小程序遇到的一些问题,其中提到了wxss的部分细节问题。这篇文章以笔者在开发小程序响应式UI当中遇到的一些问题为例,简单记录一下使用wxss为响应式开发带来的一些模式和思维上的改变。

rem的重定义

前端工程师对rem非常熟悉,rem是以html元素的font-size为基准的尺寸计量单位。rem方便了开发者对响应式UI的尺寸进行统筹管理。

wxss中的rem与css中的rem的含义完全不同,下面是微信官方文档中对rem的定义:

rem(root em): 规定屏幕宽度为20rem;1rem = (750/20)rpx

其中的750这个数值是wxss将设备屏幕的宽统一定义为750rpx,对此,下文会讲解。

各位读到这里是否脑海里浮现了一个想法:wxss的rem怎么听起来有点像bootstrap的栅格系统呢?

wxss将屏幕宽分为20rem,bootstrap将设备屏幕宽度分为12列。初看起来确实有点类似。但其实wxss的rem和bootstrap的栅格系统并不相同。虽然wxss和bootstrap都是讲屏幕尺寸分割为单元格,但rem和栅格的定位不同。

bootstrap的开发者使用指定的classname进行元素间的比例分配,这其实接近为css3中的flexbox;而wxss的rem是一个尺寸单位,你可以在合理的场景下将任何以px为单位的属性值替换为rem

所以,开发小程序UI时,需要抛弃思维中对rem的常规认知。截止目前,笔者还未遇到必须使用小程序rem的需求,希望大家踊跃探讨。

rpx的奇妙之处

上文提到wxss将设备屏幕的宽统一定义为750rpx,其中的rpx是wxss带来的新的尺寸单位。rpx的定义如下:

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

css中的px与设备的物理像素并非绝对的一比一关系。尤其是在移动设备上,px与物理像素的比例与设备的dpr(devicePixelRadio)有关,详细的对应关系各位可自行查阅。

rpx称为相对像素值,rpx与物理像素也并非绝对的一比一关系。wxss将设备宽定义为750rpx,是以iPhone6的分辨率(750x1334)为基准划分的。也就是说,在iPhone6上,1rpx=1物理像素=0.5px。官方文档列出了几种屏幕的rpx对应关系如下:
《微信小程序七日谈》- 第二天:你可能要抛弃原来的响应式开发思维第1张

大家可以从中得到rpx和px的换算公式:

1rpx = 1px/dpr

其中iPhone6的dpr=2。

那么rpx带给响应式UI什么改变呢?

目前大部分UI工程师在制作UI稿的时候是按照iPhone6的尺寸设计,然后前端工程师按照UI稿尺寸的一半进行UI的还原开发。这样在iPhone6以及接近iPhone6尺寸的设备上是没有任何问题的。但是移动设备的尺寸多种多样,我们的产品不可能只应对iPhone6(况且iPhone7已经来了哈哈...),所以通常的做法是使用css的媒体查询根据设备的尺寸再进行适配微调。

如果使用rpx是不是就可以解决这个问题呢?笔者在开发过程中尝试使用rpx代替px,使用UI稿的原始尺寸还原UI,截止到目前体验非常好。rpx本身代表的是相对像素,所以不论多大尺寸的屏幕,rpx的UI占据的屏幕比例是绝对固定的,是等比缩放的。

但是rpx并非万能的,比如使用css sprites的图标。请看下文。

sprites图标的响应式处理

使用css sprites作为图标背景时,每个图标的尺寸是以px为单位固定的,比如:

.icon{
  background-image: url('//image.daojia.com/icon.png');
  display: inline-block;
  vertical-align: middle;
}
.icon__circle{
  background-position: 0 0;
   40px;
  height: 40px;
}

如果图标的尺寸不符合UI设计,则进行一定比例的缩放:

.icon__circle{
	transform: scale(0.5);
}

也就是说,使用sprites图标不可避免地会用到px,如果与rpx结合使用,是不能保证同rpx一样等比缩放效果的。那么怎么去解决这个问题呢?

根据上文总结出的rpx与px的换算公式,如果想要将以px规定的UI达到同rpx一样的响应式缩放效果,必须将px与设备的dpr进行计算。但是css作为一种标记语言,并不具备动态特性,无法动态地获取设备dpr并计算。所以,单纯使用wxss并不能解决上文提到的问题。

好消息是小程序提供了获取设备信息的API,并且支持CommonJS模块化方案。有了这些功能,我们可以在封装组件时加入动态的逻辑配置。

还是以上文的代码为例,sprites图的icon__circle尺寸为40px*40px,我们的目标是将其适配为20rpx,以下是笔者的开发方案。

比如项目中有一个user组件,包含了一些sprites图标节点。user组件的文件目录如下:

  • user.wxml - 组件模板;
  • user.wxss - 组件样式;
  • user.js - 组件逻辑。

首先给user.wxml中icon对应的element设置动态的transform

<view   style="transform: scale({{iconScale}})"></view>

其中iconScale是引用user的外部组件index传递给user组件的:

<import src='http://t.zoukankan.com/user.wxml'/>
<template is='product-user' data="{{iconScale: userIconScale}}"/>

userIconScale是index组件的一个data,userIconScale的值并非index组件规定的,而是由index组件的js调用user.js动态获取的。以下代码是user.js暴露的API:

const ORIGIN_ICON_PX = 40;
const TARGET_ICON_RPX = 20;

module.exports = {
  getIconScale() {
    let result = 1;
    wx.getSystemInfo({
      success: function(res) {
        let _dpr = res.pixelRatio;
        result = TARGET_ICON_RPX/(ORIGIN_ICON_PX * _dpr);
      }
    });
    return result;
  }
}

然后在index组件的js中调用以上API:

let getIconScale = require('user.js').getIconScale;
Page({
	data: {
		userIconScale: 1
	},
	onLoad(){
		this.setData({
			userIconScale: getIconScale()
		});
	}
});

以上只是初步的方案,很多地方需要再仔细琢磨。不过以上方案基本上具备了一个组件的逻辑封装,并且达到了我们对响应式的开发需求。

总结

第二天的开发经历还是颇有收获的,不仅仅是对小程序开发模式的熟悉,而且对一些综合方案也有一定的深入。期待后续吧。

免责声明:文章转载自《《微信小程序七日谈》- 第二天:你可能要抛弃原来的响应式开发思维》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Eclipse的常见使用错误及编译错误sqoop笔记下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

DNS_PROBE_FINISHED_NO_INTERNET 之解决

某日电脑无法上网 wifi显示黄色叹号 确定同wifi下设备连接正常 使用windows自带的网络诊断 提示无法处理  也没有问题提示信息 开个浏览器提示 DNS的错误 ‘DNS_PROBE_FINISHED_NO_INTERNET’ 查之 找到了如下三味药剂 netsh int ip reset  //- 重置 IP 配置 netsh winsock r...

css的常用效果总结

1.模糊遮罩效率,模糊滤镜效果 -webkit-filter: blur(3px); -moz-filter: blur(3px); -o-filter: blur(3px); -ms-filter: blur(3px); filter: blur(3px); 2.渐变 background:-moz-linear-gradient(left,#ace,#...

关于ZFS、GPT、4K、Geom Label的一些说明

日前重建了之前被玩坏的zfs,碰到几个概念,查了很多资料,理清一下一、关于硬盘分区表目前常用的有两种分区表,MBR和GPT,但是严格来说ZFS并不需要任何一种分区表,ZFS可以直接管理裸盘,换句话说,zfs对硬盘有自己的管理方式,不需要经过MBR或者GPT这一层二、Geom Label和GPT分区表冲突的问题Geom Label使用glabel命令创建,会...

vue-resource+element upload上传(遇到formData总是变为object格式)

文件上传这种业务需求很常见,但是最近用了element,仔细看了文档,按照demo写了上传,与后台传参调取接口时,控制台总是显示未获取到文件,想了又想,发现一开始思路就跑遍了。。。 写此博记录下遇到的问题。 传参给后台需要formdata格式的,这种格式也很常见,如下: // FormData 对象 var form = new FormData();...

CUDA之初体验——数组求和

在高性能计算领域,GPU因为其架构的原因,在并行计算领域正发挥越来越多的用途,比如进行大量计算的游戏、绘图、图像算法等方面,采用GPU进行加速可以得到显著的性能提高。如今,Nvidia显卡在pc上的普及,cuda正是nvidia推出的通用并行计算架构。 下面在学习《深入浅出CUDA》的基础上初次体验下CUDA。 1.工程设置 这个就不多说了,新建一个空的W...

vue-cli 2.x和3.x配置移动端适配px自动转为rem

移动端适配一直都是个大问题,现在也出现了各种各样的解决方案,比如 rem, vw 百分比等,但是比较成熟的切比较容易编写的还是 rem,他是相对于根元素的 font-size 进行等比例计算的。 但是我们在编写css的时候,需要计算每一个元素相对于根元素的rem值是多少。会比较麻烦,并且维护起来也不方便。那么社区也出现了各种解决方案。 早期的解决方案是利用...