从微信小程序开发者工具源码看实现原理(四)- - 自适应布局
从前面从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计可以知道,小程序大部分是通过web技术进行渲染的,也就是最终通过浏览器的dom tree + cssom来生成渲染树;既然最终是通过css来绘制ui布局,我们知道小程序提供的自适应css单位rpx
在浏览器环境根本不被识别,所以小程序最终还是将rpx
单位转化为浏览器识别的css长度单位,到底是怎么转化的呢,本节就来探讨一下转化机制。
小程序样式转换
在从微信小程序开发者工具源码看实现原理(二)- - 小程序技术实现中可以知道,小程序中的wxss样式文件进行的主要转换转换rpx单位,视图层模板注入转换后的wxss代码如下图:
上面的内容就是注入到视图层pageframe模板中的css代码,其内容包括:
- 提供rpx单位到px单位的转换
- 提供动态插入转换后样式内容到dom中的js方法
- 每个页面引入公共样式,即app.wxss转换后的css内容
上面提到的这些转换操作都是内置到小程序的wcsc
可执行程序中,通过调用可执行程序来完成具体转换工作。最终注入到页面中的css内容如下图所示:
小程序自适应单位rpx转换
小程序的自适应布局采用的内部实现的rpx
来完成,但是其不被web识别,所以rpx
单位转换是指:
是将小程序的css单位rpx转换为web识别的css单位px
那么小程序怎么来进行rpx与px之间的转换呢?先来看一下官网有关rpx的描述:
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
由此可以看出,小程序在实现rpx转换时,不论是什么屏幕的手机,都是将屏幕宽度固定设为750rpx,然后根据实际屏幕的设备像素比dpr
(dpr = 设备像素 / css像素)来进行转换的。具体对应关系如下:
1rpx = (number/ 750) * 设备宽度 px
下面通过小程序开发者工具简单分析小程序wcsc
可执行命令程序生成的有关rpx转换的js代码
首先获取小程序的设备宽度
小程序开发者工具在初始渲染一个页面时会首先获取设备宽度deviceWidth和dpr,然后会通过checkDeviceWidth
方法(wcsc可执行命令注入的代码)检查修正二者的值,因为屏幕orientation方向可能变化,在上面代码有这么一段:
if (window.screen.orientation && /^landscape/.test(window.screen.orientation.type || "")) {
newDeviceWidth = newDeviceHeight;
}
该代码利用window.screen.orientation
来判断手机的横竖方向,若处于横屏的时候,webview的宽度与高度值会互换,即高度值就是屏幕的真实宽度;需要注意的是小程序开发者工具的webview这一点与移动端手机表现不太一致。
另外,需要补充两点:
- 利用window.screen.orientation这个判断手机方向的特性大部分浏览器支持情况比较差,具体可以看这里。但是小程序开发者工具使用基于chrome的webview,这个是支持的。
- 代码的
window.__checkDeviceWidth__
在小程序的一些基础库(如2.3.2)中是没有定义的;但是新的版本(2.7.7)是有该方法定义的,但是从什么版本开始支持的不得而知。
rpx单位转换
正如官网所描述的,小程序将屏幕固定750rpx,然后根据当前屏幕宽度以及设置的rpx值,最终推算出rpx对应的px值。
补充一点,在设置的rpx值转换为px值大于0小于1时,不论设置的rpx值是多少,最终在dpr不是1的ios情况下会始终返回0.5px,其他情况始终返回1px;例如下面代码:
.text {
height: 1rpx;
background: #333;
}
最终在开发者工具中转换的px值为0.5,如下图:
小程序屏幕旋转自适应转换过程
通过上面转换rpx值,一旦转换完成后转换值就固定了;但是对于支持屏幕旋转的情况,这显然不是我们希望的结果,期望根据屏幕旋转的方向来重新转换对应的rpx值。
小程序从2.4.0基础版本开始通过配置"pageOrientation": "auto"
开始支持屏幕旋转,这就需要知道屏幕发生变化的时机来做对应的处理。具体分两个方面转换:wxss样式文件转换和style内联样式转换。
wxss样式文件自适应转换
首先,在视图层,wxss样式文件经rpx初始转换后并将样式注入到页面过程中,会向window.__rpxRecalculatingFuncs__
数组中收集窗口变化时的回调;先看wcsc
可执行程序输出的处理rpx转换相关的setCssToHead函数实现,其最终返回rewritor函数,对应代码如下图:
可以看出在转换后的样式嵌入到document.head
中后,依然保存有创建的style元素的句柄,在页面窗口变更时执行对应的回调来修正rpx转换后的px值。
然后,在小程序基础库WAWebview内部初始时会使用wx.onWindowResize(fn)
来注册窗口变更的事件回调,注册事件内部会执行window.__rpxRecalculatingFuncs__
中的回调,具体代码如下图:
这样,视图窗口变更时就会通知样式文件进行重新rpx转换,最后将最新转换的样式内容更新到页面中。
那么,小程序如何把握屏幕切换的触发时机呢?
这个触发时机在微信环境是由native提供感知能力,开发环境则是小程序开发工具本身提供支持。拿开微信开发者工具来说明具体的整个过程:
- 视图层与业务逻辑层分别注册
onViewDidResize
事件回调 - 开发者工具感知到窗口变化会通过websocket方式向视图层和业务逻辑层同时发送执行
onViewDidResize
回调的消息 onViewDidResize
会分别执行通过wx.onWindowResize(fn)
注册的回调
内联样式自适应转换
内联样式转换在底层基础库是采用transformRpx
方法来转换rpx值的,思路与上面介绍的一样,唯一不同点就是是否对0进行修正,具体代码如下:
var $ = function(e) { // e为要转换的rpx值,V为设备宽度
return 0 === e && function(e) {
var t = window.__wcc_version_info__;
if (t) return t[e];
}("fixZeroRpx") ? 0 : (e = e / 750 * V, 0 === (e = Math.floor(e + 1e-4)) ? 1 !== dpr && isIPhone ? .5 : 1 : e)
}
通过获取window.__wcc_version_info__.fixZeroRpx
的值来判断rpx为0时如何转换;而window.__wcc_version_info__
的定义赋值是在wcc
可执行命令转换wxml文件生成的js脚本中完成的,下面是wcc生成有关赋值代码:
具体样式文件自适应转换过程如下:
- 视图层在生成virtual dom过程中会收集每个元素的属性,其中包括style属性
- 在生成dom过程中,针对元素的style属性使用
transformRpx
进行转换,转换后内容应用到具体dom元素 - 为含有rpx单位内联样式dom元素绑定窗口变化回调,窗口变化时style中的rpx进行重新转换并应用到dom元素上
从微信小程序开发者工具源码看实现原理(四)- - 自适应布局的更多相关文章
- 从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计
使用微信小程序开发已经很长时间了,对小程序开发已经相当熟练了:但是作为一名对技术有追求的前端开发,仅仅熟练掌握小程序的开发感觉还是不够的,我们应该更进一步的去理解其背后实现的原理以及对应的考量,这可能 ...
- 从微信小程序开发者工具源码看实现原理(三)- - 双线程通信
文章概览: 引言 小程序开发者工具双线程通信的设计 1.on: 用来收集小程序开发者工具触发的事件回调 2.invoke:以api方式调用开发工具提供的基础能力 3.publish:用来向Appser ...
- 从微信小程序开发者工具源码看实现原理(二)- - 小程序技术实现
wxml与wxss的转换 1.wxml使用wcc转换 2.wxss使用wcsc转换 开发者工具主入口 视图层页面的实现 视图层页面实现技术细节 视图层快速打开原理 视图层新打开页面流程 业务逻辑层页面 ...
- 微信小程序一键生成源码 在线制作定制功能强大的微信小程序
微信小程序发展到现在,短短的一年不到的时间(很快就要迎来微信小程序周年庆),在快迎来周年庆之际,百牛信息技术bainiu.ltd特记录一下这个发展的历程,用于将来见证小程序发展的辉煌时刻,我们还能知道 ...
- 解决微信小程序开发者工具输入框焦点问题
Windows10笔记本上运行微信小程序开发者工具,输入框(input,textarea)没有焦点,只能在真机调试,效率太低.后来发现是Window10对笔记本高分屏支持不好,要DPI缩放,导致兼容性 ...
- 微信小程序开发者工具详解
一.微信小程序web开发工具下载地址 1.1 在微信公众平台-小程序里边去下载开发工具下载地址. 1.2 下载后安装一下就可以使用了: 二.创建项目 2.1 微信小程序web开发工具需要扫码登陆,所以 ...
- 微信小程序支付前端源码
//index.js Page({ data: { }, //点击支付按钮进行支付 payclick: function () { var t = this; wx.login({ //获取code换 ...
- 微信小程序开发者工具构建npm提示没找到node_modules目录
一.官网给的文档写的不够充分,需要你充分理解npm的使用方法,才能明白的: 二.第一步:先在你电脑上安装npm 参考下面文章 https://www.cnblogs.com/zmdComeOn/p/1 ...
- 微信小程序开发者工具更新后报很多错误
很有可能是不小心改动微信开发者工具的基础库版本了, 在文件 project.config.json 中 "libVersion": "2.9.3", 变成 &q ...
随机推荐
- qt获得本地IP的方法,qt中域名解析的方法
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境:Ubuntu10.04 + Qt4.7.0 Linux获得本地IP的方法,我尝试了两种 1.用QH ...
- Controls 属性与继承 TShape 类的小练习(使用TShape可以解决很多图形问题)
本例效果图: 代码文件: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, ...
- impala学习笔记
impala学习笔记 -- 建库 CREATE DATABASE IF NOT EXISTS database_name; -- 在HDFS文件系统中创建数据库,需要指定要创建数据库的位置. CREA ...
- ECMAScript6 语法
声明变量 var let const var(声明局部变量,有局部外可用缺陷) 代码 <!DOCTYPE html> <html lang="en"> &l ...
- What?Tomcat-竟然也算中间件?
关于 MyCat 的铺垫文章已经写了两篇了: MySQL 只能做小项目?松哥要说几句公道话! 北冥有 Data,其名为鲲,鲲之大,一个 MySQL 放不下! 今天是最后一次铺垫,后面就可以迎接大 Bo ...
- CentOS7.5上FTP服务的安装与使用
1.FTP简介 1.1FTP:File Transfer Protocol 文件传输协议 FTP是用于在网络上进行文件传输的一套标准协议,使用客户/服务器模式.它属于网络传输协议的应用层.文件传送(f ...
- C#常用设计模式--单例模式
为什么要使用单例模式 在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个.这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁. 单例模式一般应用于管理器类,或者是一些需要持久化存在的 ...
- 基于cxf开发的WebService
Node.jshttps://www.cnblogs.com/goldlong/p/8027997.htmlQQ音乐apihttps://juejin.im/post/5a35228e51882506 ...
- LBXF时间管理法2.0
前言 LBXF是柳比歇夫的中文拼音缩写,下文中会着重介绍柳比歇夫 时间管理法主要帮助我们提高生产性时间,以及提高生产效率.我会按照柳比歇夫.执行步骤.时间管理工具Toggle三个模块来讲解LBXF时间 ...
- 关于java中构造方法、实例初始化、静态初始化执行顺序
在Java笔试中,构造方法.实例初始化.静态初始化执行顺序,是一个经常被考察的知识点. 像下面的这道题(刚刚刷题做到,虽然做对了,但是还是想整理一下) 运行下面的代码,输出的结果是... class ...