webview布局适配实践

一、相关概念

1、viewport:移动设备(包括webview)用来显示网页的那一块区域;
2、devicePixelRatio属性(别名像素比,简称dpr):window.devicePixelRatio =物理像素 / 独立像素(css中的px);
3、rem:相对于根元素(即html元素)font-size计算值的倍数(我以前真不大清楚)。

上面许多概念请看这篇 http://www.cnblogs.com/2050/p/3877280.html

二、淘宝flexible.js

下面是flexible.js的源码:

;(function(win, lib) {var doc = win.document;var docEl = doc.documentElement;var metaEl = doc.querySelector('meta[name="viewport"]');var flexibleEl = doc.querySelector('meta[name="flexible"]');var dpr = 0;var scale = 0;var tid;var flexible = lib.flexible || (lib.flexible = {});if (metaEl) {console.warn('将根据已有的meta标签来设置缩放比例');var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.] )/);if (match) {scale = parseFloat(match[1]);dpr = parseInt(1 / scale);}} else if (flexibleEl) {var content = flexibleEl.getAttribute('content');if (content) {var initialDpr = content.match(/initial\-dpr=([\d\.] )/);var maximumDpr = content.match(/maximum\-dpr=([\d\.] )/);if (initialDpr) {dpr = parseFloat(initialDpr[1]);scale = parseFloat((1 / dpr).toFixed(2));    }if (maximumDpr) {dpr = parseFloat(maximumDpr[1]);scale = parseFloat((1 / dpr).toFixed(2));    }}}if (!dpr && !scale) {var isAndroid = win.navigator.appVersion.match(/android/gi);var isIPhone = win.navigator.appVersion.match(/iphone/gi);var devicePixelRatio = win.devicePixelRatio;if (isIPhone) {// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                dpr = 3;} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){dpr = 2;} else {dpr = 1;}} else {// 其他设备下,仍旧使用1倍的方案dpr = 1;}scale = 1 / dpr;}docEl.setAttribute('data-dpr', dpr);if (!metaEl) {metaEl = doc.createElement('meta');metaEl.setAttribute('name', 'viewport');metaEl.setAttribute('content', 'initial-scale='   scale   ', maximum-scale='   scale   ', minimum-scale='   scale   ', user-scalable=no');if (docEl.firstElementChild) {docEl.firstElementChild.appendChild(metaEl);} else {var wrap = doc.createElement('div');wrap.appendChild(metaEl);doc.write(wrap.innerHTML);}}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;}win.addEventListener('resize', function() {clearTimeout(tid);tid = setTimeout(refreshRem, 300);}, false);win.addEventListener('pageshow', function(e) {if (e.persisted) {clearTimeout(tid);tid = setTimeout(refreshRem, 300);}}, false);if (doc.readyState === 'complete') {doc.body.style.fontSize = 12 * dpr   'px';} else {doc.addEventListener('DOMContentLoaded', function(e) {doc.body.style.fontSize = 12 * dpr   'px';}, false);}refreshRem();flexible.dpr = win.dpr = dpr;flexible.refreshRem = refreshRem;flexible.rem2px = function(d) {var val = parseFloat(d) * this.rem;if (typeof d === 'string' && d.match(/rem$/)) {val  = 'px';}return val;}flexible.px2rem = function(d) {var val = parseFloat(d) / this.rem;if (typeof d === 'string' && d.match(/px$/)) {val  = 'rem';}return val;}
})(window, window['lib'] || (window['lib'] = {}));

我以前做移动端适配都采用百分百布局,通常粘贴复制下面一段代码,而且还乐此不疲

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

实际网上大部分移动端适配的方案都是rem布局外加使用flexble.js原理,其核心要点(以iPhone6为例)如下:
1、手动设置上述meta viewport( initial-scale=1.0)标签,加载flexble.js成功后会在html标签设置data-dpr=1,font-size=37.5px;
  1rem = 37.5px = doc.documentElement.getBoundingClientRect().width/10 “px”;
2、如果没有手动添加meta viewport标签,flexble.js会动态设置此标签,但是和上面的情况有区别,会执行如下流程:
  a、获取devicePixelRatio(dpr)值,iPhone6值为2;
  b、设置scale = 1/dpr = 0.5;
  c、渲染viewport标签,动态设置html标签属性data-dpr=2,font-size=75px;;
  d、rem与1的获取方式相同,只不过这里面的1rem=75px;

所以flexible.js通过这两种方式布局,如果在css文件中设置一个div标签的宽度,设计图的长度是75px,第一种方式需设置width=2rem,第二种需设置width=1rem。

  以上呈现的方式适合苹果手机,安卓手机flexble.js默认dpr值为1,所以网上大部分的结论是flexible.js不适合安卓手机,既然安卓手机devicePixelRatio 也有约等于1,2,3,为什么就不能用呢。而且flexble.js只考虑竖屏的情况,设置doc宽度不大于540px。

三、我遇到的情况

  工作中一直在安卓webview中进行web开发,从接手项目的css样式中都是100%布局,后来机器越来越多,分辨率600到1920不等,而且rom层默认设置也会对机型的分辨率有影响。关键布局是否合理,一般由产品和UI决定,原项目通过media标签对各种机型不同样式适配,冗余度和复杂度高,可维护性差。
   UI设计师通常以一种机型为基准进行设计,比如说UI设计师给的设计图是1920 x 1200,那么她会以这个机型衡量其它机型,如960 x 600的机型就应该等比例缩放。布局从视觉上看不会有差异,这才达到她理想的兼容适配。

四、修改flexible.js

  根据上面遇到的情况,如果以rem布局,在1920 x 1200分辨率下是1rem=192px,那么在960 x 600分辨率的机型中1rem = 96px,这里将document宽度十等分。既然这样我也可以运用flexble.js,只需修改相关逻辑就行,而且改动不大,修改后如下:

'use strict'
const doc = window.document;
const docEl = doc.documentElement;
let metaEl = doc.querySelector('meta[name="viewport"]');
let dpr=0,scale=0,tid=null;
let msoFlex = {};if (!dpr && !scale) {const devicePixelRatio = window.devicePixelRatio;if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                dpr = 3;} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){dpr = 2;} else {dpr = 1;}scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {metaEl = doc.createElement('meta');metaEl.setAttribute('name', 'viewport');metaEl.setAttribute('content', 'initial-scale='   scale   ', maximum-scale='   scale   ', minimum-scale='   scale   ', user-scalable=no');if (docEl.firstElementChild) {docEl.firstElementChild.appendChild(metaEl);} else {const wrap = doc.createElement('div');wrap.appendChild(metaEl);doc.write(wrap.innerHTML);}
}
const refreshRem = function(){const width = docEl.getBoundingClientRect().width;const rem = width / 10;docEl.style.fontSize = rem   'px';msoFlex.rem = rem;
}window.addEventListener('resize', function() {clearTimeout(tid);tid = setTimeout(refreshRem, 300);
}, false);
window.addEventListener('pageshow', function(e) {if (e.persisted) {clearTimeout(tid);tid = setTimeout(refreshRem, 300);}
}, false);
if (doc.readyState === 'complete') {doc.body.style.fontSize = 12 * dpr   'px';
} else {doc.addEventListener('DOMContentLoaded', function(e) {doc.body.style.fontSize = 12 * dpr   'px';}, false);
}refreshRem();
msoFlex.dpr = dpr;
msoFlex.refreshRem = refreshRem;
msoFlex.rem2px = function(d) {var val = parseFloat(d) * this.rem;if (typeof d === 'string' && d.match(/rem$/)) {val  = 'px';}return val;
}
msoFlex.px2rem = function(d) {var val = parseFloat(d) / this.rem;if (typeof d === 'string' && d.match(/px$/)) {val  = 'rem';}return val;
}

修改点如下:
  1、将flexible.js手动设置viewport标签的逻辑删除,如果不删除,dpr不是1的情况,在viewport标签缩放scale值是默认的1.0,1px可能就不是真正1像素宽度,那么随之而来就是你要适配1像素宽度,网上有很多方案,比如伪元素,图片代替,另一种就是缩放,所以用代码动态设置viewport标签,scale值会随dpr值变化,1px也会缩放的,这里面我一般在样式中设置1像素宽度的单位就是px,而非rem;
  2、将flexible.js对iPhone的retain屏1,2,3设置三种情况同样适用安卓机,并且document宽度由540改为不限制宽度。
  3、命名改变了,flexible改成msoFlex,为了区别flexible.js。

五、项目微调

  1在vue工程中引用mso-flex,先npm install mso-flex --save-dev,然后在main.js头部引用import "mso-flex/mso-flex.js"即可(可以用yarn)。
  2、字体的问题,一般如果UI和产品不介意字体有瑕疵的话可以不用修改,因为用rem换算的过程中,字体可能会出现奇数和小数的字体(13px或者13.343px),这样的字体像素眼看起来有模糊。如果你用的是scss样式处理器@mixin方法对data-dpr判断,根据属性值的不同,设置字体大小。
  3、rem和px转换,需安装postcss-pxtorem,在书写样式的时候直接在psd文件中量大小像素作为长宽的数值,不需要每次用计算器将px换算成rem,方便快捷。

六、vue-cli3.0使用配置

  为了观察效果,直接准备运行vue-cli工程,发现vue-cli大变样,真的体会到在前端日益发展的过程中学不动了。
  通过官网 yarn 命令启动vue服务,先后安装
  yarn add -D mso-flex;
  yarn add -D sass-loader node-sass;
  yarn add -D postcss-pxtorem;
  下面是工程目录(真的简洁很多)


上面vue.config.js是新建配置相关loader, 但是3.0不需要配sass-loader,直接可以引用,mso-flex.js在main.js 头部直接可以引用

postcss-pxtorem在package.json配置,其中“rootValue":192的值是根据设计稿的长度除10设置的。 pxtorem中,对于想忽略的px写成大写即可,诸如 width:50PX;

以上就是在webview 安卓机布局实践,没有太多原理,也非长篇大论,如果各位大神看到开心,麻烦点个赞,谢谢哈~_~,实践的代码地址:https://github.com/yuelinghunyu/mso-flex.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql count 不等于_Mysql 不同的 count 区别

不同 count 的区别&#xff1a;count(*)、count(主键 id)和 count(1) 都表示返回满足条件的结果集的总行数&#xff1b;而 count(字 段)&#xff0c; 则表示返回满足条件的数据行里面&#xff0c;参数“字段”不为 NULL 的总个数。性能&#xff1a;count(主键 id)&#xff1a;I…

Python3爬虫(四)请求库的使用requests

Infi-chu: http://www.cnblogs.com/Infi-chu/ 一、基本用法&#xff1a; 1. 安装&#xff1a; pip install requests 2. 例子&#xff1a; import requests url http://www.baidu.com r requests.get(url) print(type(r)) # 类型是str&#xff08;JSON格式&#xff09; pr…

后台通过request.setAttribute向前台传值,前台如何去获取其中的对象或属性值

讲这些&#xff0c;我们先来了解一下request.setAttribute和request.setAttribute()这两种方法的作用。 request.getAttribute("nameOfObj"); 可得到jsp页面表单中输入框内的value。&#xff08;其实表单控件中的Object的name与value是存放在一个哈希表中的&#xff…

两个用于Eclipse的TCK –开源到底有什么?

早在5月&#xff0c;Oracle就向Eclipse Foundation 授予了兼容性测试奖学金 。 在过去的几天里&#xff0c;这引起了媒体的关注&#xff0c;我只是想确保我对整个过程和详细动作有所了解。 看起来像是一见钟情的简单诚实的礼物实际上具有更多的方面。 但让我们从头开始&#xf…

尝试连接到服务器时出错请检查虚拟机管理器,Hyper-V尝试连接到服务器出错无效类的解决方法...

Hyper-V尝试连接到服务器出错无效类的解决方法Windows10安装Hyper-V后没有自动连接到本地计算机&#xff0c;手工连接失败&#xff0c;提示&#xff1a;引用内容尝试连接到服务器"DESKTOP-6P9L2HB"时出错。请检查虚拟机管理服务是否正在运行以及是否授权你连接到此服…

Flask和mysql多线程_Flask解析(二):Flask-Sqlalchemy与多线程、多进程

Sqlalchemyflask-sqlalchemy的session是线程安全的&#xff0c;但在多进程环境下&#xff0c;要确保派生子进程时&#xff0c;父进程不存在任何的数据库连接&#xff0c;可以通过调用db.get_engine(appapp).dispose()来手动销毁已经创建的engine&#xff0c;然后再派生子进程。…

深入理解redis数据类型

转载请注明出处&#xff1a;https://www.cnblogs.com/wenjunwei/p/9720033.html redis的存储模型 redis不是普通的键值对存储&#xff0c;它实际上是一个数据结构存储服务器&#xff0c;可以支持不同类型的值。这意味着redis相比传统键值对字符串key和字符串value存储来说&…

centos7 登陆报错 grep:write error

出现这个原因是因为磁盘空间满了 通过df -h查看存储空间 发现磁盘空间满了&#xff0c;可以用 find / -type f -size 1000M 查找大于1000M的文件删除 然后找到用rm -rf 命令删除 然后就不会出现这个问题了&#xff01;转载于:https://www.cnblogs.com/lxs1314/p/8961113.html

你敢在post和get上刁难我,就别怪我装逼了

> 掘金编辑提醒&#xff1a;本文疑似有误&#xff0c;参考 听说「99% 的人都理解错了 HTTP 中 GET 与 POST 的区别」 之前好几次面试都被问到post和get有什么区别&#xff0c;肯定很多同学和我一样说了一大堆什么post比get安全&#xff0c;get比post传的少乱起八糟这样的答案…

昂首阔步:让开发人员喜欢使用您的REST API

随着JAX-RS API的发展&#xff0c;以及今年早些时候在JSR-339下发布的2.0版本&#xff0c;使用出色的Java平台创建REST服务变得更加容易。 但是&#xff0c;极大的简化带来了巨大的责任&#xff1a;记录所有这些API&#xff0c;以便其他开发人员可以快速了解如何使用它们。 不…

thinkphp mysql 更新_THINKPHP5修改数据库数据出现“缺少更新条件”的错误

查询数据库的数据分配显示在页面山修改后的数据准备传递到第三章图里接收数据&#xff0c;然后修改到数据问题出现的环境背景及自己尝试过哪些方法相关代码// 请把代码文本粘贴到下方(请勿用图片代替代码)第一张图代码public function edit(){$db_01new DB();$id_editRequest::…

angular ajax get post 参数,Angular的Post 传递参数问题及解决方法

一、传递参数过程中POST会出问题&#xff0c;问题来源&#xff1a;我们都知道向后台传参可以使用get、post&#xff0c;其形式类似于nameiyy&id001 。但是在angular中却发现使用$http post 进行异步传输的过程中后台是接收不到数据的&#xff0c;其实这个问题就是因为请求头…

[No0000187]可能是把Java内存区域讲的最清楚的一篇文章

写在前面&#xff08;常见面试题&#xff09; 基本问题&#xff1a; 介绍下 Java 内存区域&#xff08;运行时数据区&#xff09;Java 对象的创建过程&#xff08;五步&#xff0c;建议能默写出来并且要知道每一步虚拟机做了什么&#xff09;对象的访问定位的两种方式&#xff…

Java语言基础及java核心

一、Java语言特点 1、 简单 2、 面向对象 3、 分布式 4、 健壮 5、 安全 6、 中性架构跨平台 7、 超强的可移植性 8、 高性能 9、 多线程 二、java的环境变量 JAVA_HOMEC:\Program Files\Java\jdk1.8.0_101 &#xff08;到你的安装目录下&#xff09; CLASSPASH./ &#xff0…

如何使用Quartz Scheduler和日志记录创建Web应用程序

我有时会在Quartz Scheduler论坛中为用户提供帮助。 有时&#xff0c;有人会问他/她如何在Web应用程序中设置Quartz。 实际上&#xff0c;这是一件相当简单的事情。 该库已经带有一个ServletContextListener &#xff0c;您可以使用它启动调度程序。 我将在这里向您展示一个简单…

移动端日期选择插件rolldate

rolldate为上一版jquery移动端时间插件的全新版本&#xff0c;目前保留了上一版的大部分功能&#xff0c;并且增加了回调函数&#xff0c;以及主题风格选取&#xff0c;最重要的是解决了上一版本的遗留问题&#xff0c;依赖jquery、滑动不够流畅、参数设计不够合理等等。开发日…

ik分词器 mysql php_php环境下使用elasticSearch+ik分词器进行全文搜索

首先需要说明的一点是&#xff0c;如果需要启用ik分词器&#xff0c;那么分词器的版本必须与es版本一致&#xff0c;即6.3.0的分词器需要同样6.3.0版本的es支持。安装javawin-64bit的安装包需要去java英文官网查找安装ES6.3.0版本es下载地址&#xff1a;https://www.elastic.co…

服务器如何查看gpu型号,linux 查看服务器gpu

linux 查看服务器gpu 内容精选换一换本节操作介绍通过华为云APP连接Linux实例的操作步骤。云服务器状态为“运行中”。已获取Linux云服务器用户名和密码&#xff0c;忘记密码请参考在控制台重置云耀云服务器密码重置密码。云耀云服务器已经绑定弹性公网IP。所在安全组入方向已开…

Antd-Select组件的深入用法

一、Antd-Select提供几种类型 最基础版只提供下拉功能的选择器带搜索功能的下拉选择器可多选的下拉选择器可搜索、可多选、可随意输入内容的tag下拉选择器(支持自动分词)多级联动下拉选择器搜索远程数据下拉框二、一些潜在用法 如果Select.Option选项的数量特别大:2k、3k... 假…

WS-Security:使用BinarySecurityToken进行身份验证

众所周知&#xff0c;WS-Security设定的目标之一是对SOAP消息强制执行完整性和/或保密。 在完整性的情况下&#xff0c;添加到SOAP消息的签名是数学过程的结果&#xff0c;该过程涉及发送者的私钥&#xff0c;从而导致加密的消息摘要。 默认情况下&#xff0c;大多数框架&…