移动端 横竖屏适配

CSS Media Queries

通过媒体查询的方式,来实现根据横竖屏不同的情况来适配样式:

@media screen and (orientation: portrait) {
	/* 竖屏 */
}
@media screen and (orientation: landscape) {
	/*横屏 css*/
}

window.matchMedia()

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);

window.innerHeight/window.innerWidth

一种最为简单的方法是通过比较页面的宽高,当页面的高大于等于宽时则认为是竖屏,反之则为横屏。

function detectOrient(){
    if(window.innerHeight >= window.innerWidth) {
        // 竖屏
    }else {
        // 横屏 
    }
}
detectOrient();
window.addEventListener('resize',detectOrient);

window.orientation

绑定orientationchange旋转事件来判断横竖屏
在 iOS 平台以及大部分 Android 手机都有支持这个属性,它返回一个与默认屏幕方向偏离的角度值:
0:代表此时是默认屏幕方向
90:代表顺时针偏离默认屏幕方向90度
-90:代表逆时针偏离默认屏幕方向90度
180:代表偏离默认屏幕方向180度
如下图所示:
移动端 横竖屏适配_第1张图片
在实际应用中,对于 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);
}

你可能感兴趣的:(移动端,移动端适配)