[toc]
移动端适配方案flexible.js
出发点
事故的开始总是有原因的,那思考一下,为什么使用Flexible
?
为了
rem
布局? >> 为什么要rem
布局 ——> 高度还原移动端适配? >> 为什么移动端适配要用
Flexible
——> 同等占比什么是移动端适配?
最初点是设计图的高度还原!!!
以750*1334设计稿(iPhone6)为准,期望每一个设计元件在iPhone6实机上占比、宽高比都与设计稿显示一致。
一套代码又想扩展到其它设备,于是出现了rem
布局
-
Flexible
做了什么 -
rem
是什么 - 如何做到高度还原设计图的
引入flexible.js
在
*.html
的<head>
标签中引入<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
flexible.js
会做以下几件事:
- 给
*.html
添加内联样式表- 只是reset一些样式
- 给
<html>
设置[data-dpr=""]
属性、font-size
样式-
[data-dpr=""]
属性- 通过属性选择器,设置不同分辨率下的样式
- 主要是针对字号
-
font-size
-
rem
单位的基准尺寸
-
-
- 监听
resize
、pageshow
事件来重新设置html.style.fontSize
- 设置
body.style.fontSize
- 定义全局变量window.lib.flexible
window.lib.flexible = {
dpr: number,
refreshRem: function,
rem2px: function,
px2rem: function
}
Note:HTML
中无需设置meta#viewport
,flexible.js
会根据window.devicePixelRatio
的值自动添加meta#viewport
。
假设设置如下<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0">
,不管设备是多少的dpr,flexible.js
不再修改该元数据配置,都会强制认为其dpr是你设置的值。
Note:在Flexible
中,只对iOS
设备进行dpr
的判断,对于Android
系列,始终认为其dpr
为1
对于Android
系列,始终认为其dpr
为1?
深入flexible.js
的实现,是body#width
依据devicePixelRatio
进行缩放的。
而针对iOS
设备,缩放后正好为其visual viewport
的尺寸。
而针对Android
系列手头上的机器测试,不用缩放,body#width
正好为其visual viewport
的尺寸。
body#width / dpr > 540
?
若body#width / dpr > 540
,如PC端body#width > 1080
,Flexible
当1080处理。
通过scss
定义px2rem的转换
在不使用自动化工具的基础上,无法使用以下处理方式,只能自己计算后再赋值
@function px2rem($px, $base-font-size: 16px) {
@if (unitless($px)) {
@warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
@return px2rem($px + 0px); // That may fail.
} @else if (unit($px) == rem) {
@return $px;
}
@return ($px / $base-font-size) * 1rem;
}
原理:通过以上步骤,就能实现设计图的高度还原?
本质上是设计元件的同比转换。
flexible.js
将body#width
分成100份,一份为基准,设置为html#fontStyle
,而px2rem
将设计元件转换为设计图的占比*%
,以rem
为中介,在设备上的展示具有同等占比。
以此来实现设计图的高度还原。
然而,计算出来的结果可能非有效值,所以,浏览器的显示优化……
如:小于12px
的字体、浮点数的精度……
文本字号不建议使用rem
我们希望文本在相同
dpr
屏幕下文本字号相同
我们希望在大屏手机上看到更多文本
不希望出现13px和15px这样的奇葩尺寸
解决方案
文本还是使用px作为单位,只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小
在不使用自动化工具的基础上,无法使用以下处理方式,只能自己计算后再赋值
@mixin font-dpr($font-size){
font-size: $font-size;
[data-dpr="2"] & {
font-size: $font-size * 2;
}
[data-dpr="3"] & {
font-size: $font-size * 3;
}
}
@include font-dpr(16px);
补充知识点
-
flexible.js
使用document.readyState API
获取document
的加载状态
document.addEventListener('readystatechange', event => {
if (event.target.readyState === 'interactive') {
// 等同于DOMContentLoaded 事件
}
else if (event.target.readyState === 'complete') {
// 表示 load 状态的事件即将被触发。
// 等同于loaded
}
});
在Vue
项目中的实战
项目由@vue/cli@4.5.13创建的
移动端适配
引入flexible
- 安装
lib-flexible
npm i -D lib-flexible
- 项目中引入
flexible
# main.js import "lib-flexible/flexible";
Note: 直接在HTML
模板的<head>
中引用,执行的优先级会更高
样式px
自动转rem
-
安装
postcss-plugin-px2rem
npm i -D postcss-plugin-px2rem
-
创建
.postcssrc.js
# .postcssrc.js module.exports = { plugins: { 'postcss-plugin-px2rem': { rootValue: 108, //换算基数,设计图尺寸, 默认100 exclude: /(node_module)/, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)\/ mediaQuery: false, //(布尔值)允许在媒体查询中转换px。 minPixelValue: 3, //设置要替换的最小像素值(3px会被转rem)。 默认 0 } } }
-
凡事有例外
若不想转换rem
,单位使用全大写PX
,如字体# presets.scss $largeFont: 40PX; $middleFont: 20PX; $standardFont: 14PX; $smallFont: 10PX; @mixin font-dpr($font){ font-size: $font; [data-dpr="2"] & { font-size: $font * 2; } [data-dpr="3"] & { font-size: $font * 3; } }
# example.scss ... @import "../../assets/scss/preset"; .page-title{ @include font-dpr($standardFont); } ...
规范提交记录
通过以下命令@vue/cli
会自动安装commitlint
插件并更新pkg
vue add commitlint
swiper
应用
- 安装依赖
npm install swiper vue-awesome-swiper --save
- 全局注册
# main.js ... import VueAwesomeSwiper from "vue-awesome-swiper"; import "swiper/swiper.scss"; Vue.use(VueAwesomeSwiper, {}); ...
- 逻辑应用
# Example.vue <template> <swiper ref="mySwiper" :options="swiperOptions"> <swiper-slide v-for="i in 5"> <div> Slide {{i}} </div> <button @click="handleClickItem(i)">点击后才可滑动</button> </swiper-slide> </swiper> </template> <script> export default { name: "Example", data() { return { swiperOptions: { direction: "vertical", }, }; }, methods: { handleClickItem(idx) { // 满足某条件后可滑动 this.swiper.allowSlideNext = true; }, }, computed: { swiper() { return this.$refs.mySwiper.$swiper; }, }, mounted() { // 默认禁止滑动翻页 this.swiper.allowSlidePrev = false; this.swiper.allowSlideNext = false; // 翻页后禁止翻页 this.swiper.on("slideChange", () => { this.swiper.allowSlideNext = false; this.currentIdx = this.swiper.activeIndex; }); }, }; </script>
- 样式
# example.scss .swiper { &- { &container { height: 100%; } &slide { height: 100%; color: white; } } } button { position: absolute; z-index: 100; bottom: 20PX; width: 100%; text-align: center; }
非标准字体
非标准字体是指人为调整系统设置中的字体字号大小。
(function () {
var $dom = document.createElement("div");
$dom.style = "font-size:20px;";
document.body.appendChild($dom);
// 计算出放大后的字体
var scaledFontSize = parseInt(
window.getComputedStyle($dom, null).getPropertyValue("font-size")
);
document.body.removeChild($dom);
// 计算原字体和放大后字体的比例
var scaleFactor = 20 / scaledFontSize;
// 取html元素的字体大小
// 注意,这个大小也经过缩放了
// 所以下方计算的时候 *scaledFontSize是原来的html字体大小
// 再次 *scaledFontSize才是我们要设置的大小
var originRootFontSize = parseInt(
window
.getComputedStyle(document.documentElement, null)
.getPropertyValue("font-size")
);
document.documentElement.style.fontSize =
originRootFontSize * scaleFactor * scaleFactor + "px";
alert(
parseInt(
window
.getComputedStyle(document.documentElement, null)
.getPropertyValue("font-size")
)
);
})();
上述章节我们说【不推荐】字号使用rem
,而使用px
,是因为想让不同设备像素比的设备更大的程度利用展示空间:大屏一行展示的文本更多,小屏展示的少一些。
而考虑非标准字体,若字号使用px
,即使通过上述方法调整html
的基准字号大小,也不会影响字体的展示。
所以,考虑非标准字体时,字号需要使用rem
设置。
Pad适配
现在Pad
盛行,要考虑适配Pad
.
对于Pad
的适配,Flexible
并没有考虑,而我们可以稍作修改进行适配。
Flexible
并没有考虑Pad
,通过修改var isIPhone = win.navigator.appVersion.match(/iphone|iPad/gi);
调整-
Flexible
针对设备有最大尺寸限制,将其去掉即可function refreshRem(){ var width = docEl.getBoundingClientRect().width; // if (width / dpr > 540) { // width = 540 * dpr; // } var rem = width / 10; docEl.style.fontSize = rem + 'px'; flexible.rem = win.rem = rem; }
-
px2rem
的媒体查询配置- 删除
postcss-plugin-px2rem
插件及其配置 - 自定义px转rem函数 —— 为了媒体查询
//# px2rem.scss $defaultFontSize: 108; @function px2rem($px, $baseFontSize: $defaultFontSize) { @return $px / $baseFontSize * 1rem; }
.main { width: px2rem(540); @media screen and (min-width: 450px) { width: px2rem(1660, 166); } }
- 删除
参考文档
// px2rem
https://juejin.cn/post/6844903780673142792
// commitlint
https://juejin.cn/post/6844904004749623309