通过媒体查询的方式,来实现根据横竖屏不同的情况来适配样式:
@media screen and (orientation: portrait) {
/* 竖屏 */
}
@media screen and (orientation: landscape) {
/*横屏 css*/
}
CSS Object Model(CSSOM)Views 规范增加了对 JavaScript 操作 CSS Media Queries 的原生支持。我们能够通过脚本的方式来实现媒体查询
window.matchMedia() 方法接受一个 Media Queries 语句的字符串作为参数,返回一个对象。
该对象有 media 和 matches 两个属性:
media:返回所查询的 Media Queries 语句字符串
matches:返回一个布尔值,表示当前环境是否匹配查询语句
该对象还包含了两个监听事件:
addListener(callback):绑定回调 callback 函数
removeListener(callback):注销回调 callback 函数
var mql = window.matchMedia("(orientation: portrait)");
function onMatchMeidaChange(mql){
if (mql.matches) {
// 竖屏
} else {
// 横屏
}
}
onMatchMeidaChange(mql);
mql.addListener(onMatchMeidaChange);
一种最为简单的方法是通过比较页面的宽高,当页面的高大于等于宽时则认为是竖屏,反之则为横屏。
function detectOrient(){
if(window.innerHeight >= window.innerWidth) {
// 竖屏
}else {
// 横屏
}
}
detectOrient();
window.addEventListener('resize',detectOrient);
绑定orientationchange旋转事件来判断横竖屏
在 iOS 平台以及大部分 Android 手机都有支持这个属性,它返回一个与默认屏幕方向偏离的角度值:
0:代表此时是默认屏幕方向
90:代表顺时针偏离默认屏幕方向90度
-90:代表逆时针偏离默认屏幕方向90度
180:代表偏离默认屏幕方向180度
如下图所示:
在实际应用中,对于 iPhone 和大部分 Android 是没有180度的手机竖屏翻转的情况的,但是 iPad 是存在的。
function recordOrient() {
if (window.orientation === 180 || window.orientation === 0) {
//竖屏
} else if (window.orientation === 90 || window.orientation === -90) {
// 横屏
}
}
recordOrient();
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {
recordOrient();
}, false);
1)对window.orientation属性值的不一致
在 iOS 平台是无异议的,规范当中有明确规定每个值对应的情况。但是对于 Android 平台,就有不一致的特殊情况出现,部分 Android 机型返回的情况是与期望情况是相反的。
针对这种不一致情况的出现,对于追求完美的开发者来说,通过 window.orientation 的方法来判断横竖屏则变得有点不可靠。
2)软键盘的弹出
在 Android 下,如果页面中出现软键盘弹出的情况(存在有 Input 的元素)时,页面有时会因为软键盘的弹出而导致页面回缩,即页面的宽度(竖屏时)或者高度(横屏时)被改变。
所以通过 CSS多媒体查询(CSS Media Queries) 、 window.matchMedia() 方法、window.innerWidth /window.innerHeight的页面宽高比对方法来实现的横竖屏判断方法,都会因此受到影响,出现判断失误的情况( Samsung SCH-i699 机型,在竖屏时由于软键盘弹出导致页面高度小于宽度,被错误地判定为横屏)。
所以,在这样的情况下,这几种方式也变得不可靠。
解决办法:
CSS 媒体查询:给一个横屏的最小宽度
@media screen and (orientation: portrait) {
/* 竖屏 */
}
@media screen and (orientation: landscape) and (min-width: 560px) {
// 横屏
}
js判断:
针对开发环境兼容的情况( iOS 与 Android 下的微信内置浏览器与原生浏览器)来说,屏幕分辨率是不会改变的,那么我们可以尝试比对页面宽高和屏幕分辨率来判断横竖屏。在移动端,屏幕翻转时,screen.width 和 screen.height 的值依然是不变的)。
若当前页面的宽(document.documentElement.clientWidth),等于屏幕分辨率的宽(screen.width),则可认定当前属于竖屏。反之,当前页面的宽等于屏幕分辨率的高,则可认定当前属于横屏。
function recordOrient() {
var w = document.documentElement.clientWidth,
var _Width = window.screen.width;
var _Height = window.screen.height;
if(w == _Width) {
// 竖屏
return;
}
if(w == _Height){
// 横屏
return;
}
}
recordOrient();
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {
recordOrient();
}, false);
3)msdk游戏接入强制竖屏
a)在 iOS 锁屏情况下,强制竖屏不成功。
需要做横屏适配,而在 iOS平台,会有默认安全区域空白,需要定义页面宽高等于手机视口宽高
解决方法:做横屏适配,并提示开启屏幕自动旋转
@media screen and (orientation: landscape) and (min-width: 560px) {
#app{ //定义页面宽高等于手机视口宽高
width: 100vw;
height: 100vh;
background: #fff;
position: relative;
}
.msdk .container{ //横屏时不显示页面内容
display: none;
}
/deep/ .shine-landscape{ // 横屏适配页
display: block;
}
}
b)使用window.orientation判断旋转事件,ios旋转横屏会出现横屏判断成功,显示横屏适配页,但视图布局为竖屏。
上面的问题为什么要用媒体查询做适配呢?就是因为使用window.orientation判断旋转事件判断横竖屏,ios旋转横屏会判断为横屏,但wenbview强制竖屏,布局始终保持为竖屏。所以不建议使用旋转事件判断横竖屏。当然采用另外几种适配也是没问题,但上面媒体查询方式比较简单
c) 全屏浏览器用户输入软键呼出、隐藏时webview容器高度自适应,目前发现部分机型出现软键盘出现时webview高度没有自动变化,软键盘推不上input输入框(输入框被软键盘盖住了),例如oppo find X;
c) 视频全屏播放
4)在msdk游戏接入中隐藏某些模块
在家庭守护中,隐藏部分模块的原理是根据第一个弹框携带的参数做判断,而在家庭守护中从进入的第一个页面开始,路由跳转会一直携带着判断的参数,
当从退出家庭到管理页或者初始化过程跳转到管理页,需要刷新页面,则采用了window.location的跳转方式,这里不能忘记手动携带该有的参数,否则从这里开始接下来所有页面都失去了判断的参数,项目中该去掉的模块就会出现
/**
* 获得时间戳
*/
function randomTimeStamp() {
return parseInt(new Date().getTime() / 1000) + '';
}
/**
* 检测flag
* @param search
*/
function checkFlag(search) {
if (/[&|?](flag=[\d]+)/.test(search)) {
search = search.replace(/[&|?](flag=[\d]+)/, (str) => {
let splitStrs = str.split('=');
return splitStrs[0] + '=' + randomTimeStamp();
})
} else {
if (search) {
search += '&flag=' + randomTimeStamp();
} else {
search += '?flag=' + randomTimeStamp();
}
}
return search;
}
/**
* 拼接地址
* @param path: 路由
* @param flag: 是否需要刷新
*/
function locationUrl(path, flag = true) {
let url = '';
if (flag) {
let search = checkFlag(location.search);
url = location.protocol + '//' + location.host + location.pathname + search + '#/' + path;
} else {
url = location.protocol + '//' + location.host + location.pathname + location.search + '#/' + path;
}
window.location = url;
}
this.locationUrl('Index');
5)横竖屏旋转canvas重新绘制
在使用canvas绘制图表并在移动端适配铺满的情况下,当横竖屏自动旋转时,需要监听旋转事件并刷新canvas部分的局部视图
data() {
return {
isOrientationChange: false
}
},
created() {
const _this = this;
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {
if (window.orientation === 180 || window.orientation === 0) {
//竖屏 刷新canvas
if (window.isMSDK) { // 解决iphone6 plus
_this.$router.go(0)
}
_this.isOrientationChange = true;
setTimeout(()=> {
_this.isOrientationChange = false;
}, 100)
} else if (window.orientation === 90 || window.orientation === -90) {
// 横屏 不刷新
}
}, false);
}