从flexible.js引入高德地图谈起的移动端适配
曾几何时,前端还仅仅是PC端的。随着移动时代的兴起,h5及css3的推陈出新。前端的领域慢慢的由传统的pc端转入了移动端,这也导致了前端这一职业在风口的一段时间出尽了风头。
从开始的惶恐和无从下手,慢慢的到了有了统一的技术方案去落地实现。
从手写不同尺寸的媒体查询css到以手淘的flexible.js来进行移动端的适配,虽然过程曲折,不过效果也是十分的显著,因为有了成熟的体系以后。什么东西就有据可寻,适配也就没那么困难了。
但是,因为这次引入了高德地图,所以在适配上出现了一点意料之外的问题。
首先,我要说下视口这个东西,因为手淘的这个方案是严重依赖视口这个概念的。
1.视口
1.1视口的分类
ppk将视口分为三大类:布局视口,可视视口,理想视口
那视口是什么呢?通俗点说就是就是浏览器上(也可能是一个app中的webview)用来显示网页的那部分区域,但viewport又不局限于浏览器可视区域的大小,它可能比浏览器的可视区域要大,因为为了正常的显示PC端的网页,浏览器会将自己的layout viewport设置为一个较大的值,结果就是会出现左右的滚动条。当然viewport(visual viewport)也可能比浏览器的可视区域要小,比如有的手机自带的浏览器会有一个自带的黑色小边距。

布局视口和可视视口我们作基本了解即可。在实际工作中,我们需要接触和处理的更多是ideal viewport。
而我们前端一直孜孜以求的移动端的适配。其实就是为了让用户的浏览器中呈现的是我们的理想视口
ideal viewport并没有一个固定的尺寸,不同的设备拥有有不同的ideal viewport。
早期移动端开发,对于终端设备适配问题只属于Android系列,有320pt的,有360pt的,有384pt的等等。但随着iPhone6,iPhone6+的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。有320pt的,有375pt(iphone x)的,有414pt(plus)的等等。
http://viewportsizes.com里面收集了众多设备的理想宽度。
1.2 如何影响视口?
既然viewport这么重要,那我们怎么去控制他为我所用呢?这个时候,就轮到meta标签出场了。
先来一段我们在开发的时候最常用的一句话。
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
用下面的表格来解释一下content里面的属性
| width | 设置layout viewport 的宽度,为一个正整数,或字符串"width-device" |
| height | 设置layout viewport 的高度,这个属性对我们并不重要,几乎不使用 |
| initial-scale | 设置页面的初始缩放值,相对于ideal viewport进行缩放,为一个数字,可以带小数 |
| minimum-scale | 允许用户的最小缩放值,为一个数字,可以带小数 |
| maximum-scale | 允许用户的最大缩放值,为一个数字,可以带小数 |
| user-scalable | 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许 |
<meta name="viewport" content="width=device-width">
width=device-width,通过这个特殊值。我们将layout viewport => ideal viewport
<meta name="viewport" content="initial-scale=1.0">
通过设置初始的缩放比率,我们也可以将layout viewport => ideal viewport
所以上面两种方式是殊途同归的。那么,为什么我们还要将两个都写上去呢?
答案:initial-scale=1.0是为了处理在 iphone、ipad上,无论是竖屏还是横屏,宽度都是竖屏时ideal viewport的宽度,
width=device-width是为了处理在windows phone 上的IE 无论是竖屏还是横屏都把宽度设为竖屏时ideal viewport的宽度
<meta name="viewport" content="width=400, initial-scale=1.0">
如果出现了上面的这种怎么办呢?
这个时候浏览器会取它们两个中较大的那个值。例如,当width=400,ideal viewport的宽度为320时,取的是400;当width=400, ideal viewport的宽度为480时,取的是ideal viewport的宽度。
总结起来就是“谁大谁先行“
2.引入高德后页面的表现
在vue的spa项目中引入高德以后,我们发现在不同的dpr下,地图的显示效果差距非常大。

在dpr=3的时候,也就是plus的机型上,地图显得格外的小。几乎用肉眼是无法看清上面的字体。所以,这样说来,基于flexible的适配方法肯定是有问题的了。
而出现这个问题的原因就是我们的viewport被缩放了。
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;
}
通过上面的代码计算出了viewport缩放的比率。当处于iphone 6+plus的时候,scale = 0.333333333333....
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
最后写到页面上面的结果就是:
<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">
所以,iphone plus是414pt,通过flexible将viewport缩小了0.33333333333,我们将414/0.3333333333=1242.0000001242
而正好高德地图通过canvas绘制的画布的宽度也就是1242。
3.如何解决这个问题
通过我的总结,处理这个问题的方法大致有三种
3.1 通过vue-router的路由守卫进行处理
beforeMount() {
this.$nextTick(() = >{
const dpr = document.documentElement.getAttribute('data-dpr')
if (dpr > 1) {
window.tempViewport = document.querySelector('meta[name="viewport"]').getAttribute('content');
document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
window.tempDpr = dpr;
document.documentElement.setAttribute('data-dpr', 1);
}
})
},
beforeRouteLeave(to, from, next) {
if (window.tempViewport) {
document.querySelector('meta[name="viewport"]').setAttribute('content', window.tempViewport);
delete window.tempViewport;
}
if (window.tempDpr) {
document.documentElement.setAttribute('data-dpr', window.tempDpr);
delete window.tempDpr;
}
next()
},
不过这样的方式不是很好,因为页面在过渡的时候会出现一瞬间样式的变形。而且如果在当前有地图的页面有其他结构的话,其他结构也会错乱。
Tips:如果不是SPA的应用,而且整屏页面是地图占满的情况下,这个方案还是可行的。
3.2 通过css scale属性
这个方法在我试验了以后,也存在问题。虽然地图的大小是正常了,但是在地图上进行点标记的时候,会出现地图位置的偏移。
Tips:如果仅仅是展示,而并没有任何交互的情况下,这个方式也是可行的。
3.3 通过设置dpr = 1 (推荐)
通过设置dpr=1,强制flexible布局对viewport不进行缩放。
<meta name="flexible" content="initial-dpr=1" />
这样,最后写到页面上的meta标签就是这样的。
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
既然viewport没有缩放了。高德地图通过canvas绘制的地图也就是按照我们的ideal viewport来进行处理了。
不过这种方式会产生另外两个副作用:
- 通过缩放来处理的"1px问题"这里需要重新去处理了
- 通过dpr设置的不同dpr下的文本字号大小,可能会出现13px这样很奇葩的尺寸了
第一个是适配中一个很经典的问题,我会放到随后去讲。而第二个问题只能暂时这样去处理了。
4.结尾
大漠对于这个问题的解释是:flexible已经完成自己的使命,该功成身退了。他推荐使用vw,vh标准的新布局方式。
而到底用不用这套方案,作为前端的我们也是见仁见智了!
从flexible.js引入高德地图谈起的移动端适配的更多相关文章
- vue-cli2.X中引入高德地图,将其设为全局对象
平时一般未用脚手架构建或用webpack构建的项目只要用script标签引入即可,在vue-cli 2.X构建的项目中,需要用如下方式引入高德地图: 首先在高德地图开放平台中注册开发者账号并获取key ...
- vue-element-admin 引入高德地图并做海量点标记
第一步: 首先在index.html入口文件中添加引入高德地图的js,并填写自己在官网申请的key.如果没有申请不填写也是可以的. plugin:项目中如果有需要引入插件则使用没有直接去掉就行. &l ...
- VUE 2.0 引入高德地图,自行封装组件
1. 高德地图官网 申请帐号, 申请相应(JavaScript API)的 Key 2. 在项目中引入, 这里和其他的引入不同的是 直接在 index.html, 不是在 main.js 引入, 博主 ...
- vue 里面引入高德地图
效果图: 实现: 一:引入 高德,web-sdk (两种方式) 1:在html 中引入(我用的这一种) <script type="text/javascript" src= ...
- vue.js 使用高德地图
1.获取key值 注册成为高德开发者需要分三步: 第一步,注册高德开发者: 第二步,去控制台创建应用: 第三步,获取Key 2.修改配置文件 webpack.base.conf.js externa ...
- js通过高德地图获取当前位置的经度纬度
效果图如下: 已经获取到了经度纬度了 代码如下: <!doctype html> <html> <head> <meta charset="utf- ...
- js调用高德地图API获取地理信息进行定位
<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=(需要自 ...
- js/vue 高德地图绘制驾车路线图
地图容器: // css要给此容器设置宽高 <div class="map_container"></div> 画图 data{ return { Clng ...
- js调用高德地图的搜索api
var city = $('#city')[0].value; AMap.plugin(['AMap.Autocomplete'],function(){ var autoOptions = { ci ...
随机推荐
- 关于ls命令的实例
生活映射程序---------科技创造生活 ls 是Linux的常用命令之一直接使用 ls 命令的话只会列出对应的文件名ls -l 命令会显示文件和目录,包括文件类型,大小,修改日期和时间,权限信息等 ...
- PID算法
所谓PID就是比例-积分-微分的英文缩写,但并不是必须同时具备这三种算法,也可以是 PD, PI,甚至只有 P算法控制,下面分别介绍每个参数的含义:首先需要明确一个事实就是,要实现PID算法,必须在硬 ...
- python3 第一章 - 简介
1.什么是python 引用官方的话:Python是一种易于学习,强大的编程语言.它具有高效的高级数据结构,并通过简单而有效的方法来进行面向对象编程.Python的优雅语法和动态类型,以及其解释性质, ...
- 转-Web Service中三种发送接受协议SOAP、http get、http post
原文链接:web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 一.web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 在web服务中,有三种可供选择的发 ...
- myeclipse取消js校验
最近玩一个新的项目,项目里面集成了别的项目,在从SVN上第一次荡下来的时候编译的时候老是校验jq文件,老是被卡主,设置myeclipse环境的时候我已经取消了所有的js校验了,但是还是不行.恼火之余, ...
- 重定向stdin stdout stderr |
在Linux下,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据 流,也就是题目中所提到的这三个.那么什么是数据流呢(stream)? 我们知道,一个程序要运行,需要有输入.输出,如果出错, ...
- JavaSE基础篇—数据类型和运算符
本章知识点内容概括 数据类型: 1.基本数据类型 数值型 整数类型 byte(128~127),占1个字节的储存间 short(-2^15~2^15-1),占2个字节 int(默认类型-2^3 ...
- 对List中每个对象元素按时间顺序排序
需求: 需要对List中的每个User按照birthday顺序排序,时间由小到大排列. 代码实现: import java.text.SimpleDateFormat; import java.uti ...
- 节点操作,节点属性的操作及DOM event事件
##1. 节点操作 createElement(标签名) 创建一个指定名称的元素 someone.appendChild(new_node) 追加一个子节点(作为最后的子节点) someone.ins ...
- python的组合数据类型及其内置方法说明
python中,数据结构是通过某种方式(例如对元素进行编号),组织在一起数据结构的集合. python常用的组合数据类型有:序列类型,集合类型和映射类型 在序列类型中,又可以分为列表和元组,字符串也属 ...