前端 H5 橫屏 獨特處理方案詳解

前言

隨着公司知識付費業務的發展,產品發現橫屏展現內容的效果和體驗都要比豎屏要來的好。我也感受確實是這樣的~。剛接到這個需求的時候,稍微想了一下,橫屏這還不簡單直接把整個頁面旋轉90度,不就完事了?結果然正開發的過程當中發現並無這麼簡單。好比屏幕橫過來手勢滑動的方向沒有變過來等等!因而嘗試去百度了一下最終並無搜到滿意的答案。後來決定本身摸索一下,下面是我開發過程當中總結了一套作法,有更好的作好的同窗也能夠分享指正。vue

效果圖

首先給你們看看效果圖

效果圖一: node

效果圖二:
效果圖三:

看上去仍是挺高大上的吧~,不過這效果圖是針對app原生設計的,實際H5頁面在微信裏面訪問還會有標題欄和底部返回欄,以下圖h5實際展現效果(android):android

你們能夠進去先體驗一下(用微信訪問),項目地址 m.ngmm365.com/mathbox/ind… 頁面加載完畢以後,點擊試學按鈕便可進入橫屏頁面。git

項目需求及分析

項目需求

一、需求一:效果圖一的星球要能支持左右滑動,滑動過程當中還要能支持3D(遠近縮放)的效果github

二、需求二:效果圖二會有多節課須要能支持左右滑動web

三、需求三:效果圖三內容要恰好佔一屏api

分析

一、分析需求一:星球切換部分使用swiper來實現。bash

二、分析需求二:好像沒什麼難的,使用系統默認的滾動條就能夠支持滾動了。微信

三、分析需求三:嗯~,佔一屏還不簡單!直接按效果圖尺寸寫就行了。app

實踐總結

公司使用的是vue技術棧,因此下面的組件也是基於vue來寫的。懂了原理我相信無論用什麼框架去實現都不會有太大問題,因此不懂vue的同窗也不用慌。

問題及解決方案

一、如今首先要作的第一件事情就是怎樣先讓頁面橫過來?

h5沒有橫屏屬性那隻能經過旋轉頁面的元素來達到橫屏的效果了transform: rotate(90deg);,因此咱們要首先要有一個橫屏容器組件。而後把對應頁面的內容都放在這個容器裏面頁面是否是就橫過來了?

橫屏容器組件代碼以下:

<template>
    <section v-horizontal-screen @touchmove.prevent>
        <!-- 頁面具體內容 -->
        <slot></slot>
    </section>
</template>
<script>
export default {
	directives: {
        'horizontal-screen': {
            bind(el, binding, vnode){
                let self = vnode.context;
                
                function reset(init){
                    
                    let width = document.documentElement.clientWidth,
                        height = document.documentElement.clientHeight;
                    //在豎屏狀態咱們經過添加transform:rotate(90deg),來讓這個頁面橫過來
                    if(window.orientation == null || window.orientation === 180 || window.orientation === 0){//豎屏狀態
                        el.style.webkitTransform = el.style.transform = `rotate(90deg)`;
                        el.style.width = `${height}px`;
                        el.style.height = `${width}px`;
                        el.style.webkitTransformOrigin = el.style.transformOrigin = `${width / 2}px center`;
                        //若是已經處於橫屏狀態就不作其餘處理了
                    }else if(window.orientation === 90 || window.orientation === -90){//橫屏狀態
                        el.style.webkitTransform = el.style.transform = `rotate(0)`;
                        el.style.width = `${width}px`;
                        el.style.height = `${height}px`;
                    }
                }
                reset(true);

                let timer = null;
                el.fn = function(e) {
                    clearTimeout(timer);
                    timer = setTimeout(reset, 300);
                }
                
                window.addEventListener('resize', el.fn, false);

                if("onorientationchange" in window){
                    window.addEventListener('orientationchange', el.fn, false);
                }
            },
            unbind(el, binding, vnode){
                window.removeEventListener('resize', el.fn, false);
                window.removeEventListener('orientationchange', el.fn, false);
            }
        },
    }
}
</script>
複製代碼

如今頁面已經橫過來,接下來先讓星球可以左右切換吧。是否是直接加入swiper插件就能夠了?

嘗試引入swiper插件,而後運行起來的時候會發現,手勢反了,上下滑動的時候內容纔會左右滑動。由於如今咱們只是把頁面橫過來了,x軸和y軸並無變。當咱們上下滑動的時候實際上改變的是x軸,也就是正常頁面的左右滑動。帶着好奇心查了一下swiper的api看看是否有支持這種操做參數。結果沒有查到,只好本身嘗試去修改源碼了。下面是修改代碼後的部分截圖:

增長了一個參數isReverse,若是爲true則x軸和y軸反一反。固然isReverse還要判斷一下特殊狀況好比原本app就已經橫屏了其實就不必x軸y軸互反了。這樣咱們的內容又能夠正常跟着手指方向滑動了。

前面暫定需求二的滾動方式採用默認滾動條來解決,結果實現出來以後發現手指滑動方向也是反。原生的手勢反了,改怎麼調整呢?網上查了一通沒有找到答案,關鍵這問題也不是很好描述!由於以前有使用過iscroll,能夠模擬系統滾動條的效果。嘗試加入到代碼中,發現和swiper同樣也會出現手指滑動方向反的狀況。最後也只能本身去源碼中增長一個參數了。總體對比iscroll改動的代碼要比swiper少的多。只須要改一個地方就能夠了,截圖以下:

需求一和需求二都解決了,接下來來解決「最簡單」的第三個需求。其實按照設想不用作任何其它操做,只須要按照效果圖的尺寸寫就行了。

頁面寫好了,在電腦上跑也沒什麼問題。決定部署到測試環境用手機跑一下看看。結果發現右側內容超出屏幕範圍了。是由於在微信中有標題欄和底部欄,致使內容超出了屏幕範圍。聯想一下其實在不一樣長寬比的手機上 其實即便不存在標題欄和底部欄 其實也會有相似狀況。這該怎麼解決呢?最後決定在橫屏容器組件內部再加入一個自動縮放組件,最後頁面的框架圖長下面這樣。固然自動縮放組件只在須要的地方加入。

接下來一塊兒看看比例縮放容器的代碼吧。

<template>
	<div class="scale-wrap" :style="scaleWrapStyle">

		<slot></slot>

	</div>
</template>
<script>
//這塊寬高比例根據效果圖來設置
const DesignWidth = 375;
const DesignHeight = 667;
const DesignRatio = DesignWidth / DesignHeight;

function getScale(){

    let width = document.documentElement.clientWidth,
        height = document.documentElement.clientHeight;

    if(window.orientation == null || window.orientation === 180 || window.orientation === 0){//豎屏狀態
    	
    }else {
    	[width, height] = [height, width];
    }

    let ratio = width / height;

    let scale;

    //經過計算實際手機寬高比和效果圖的寬高比得出最終的所讓比例
    if(ratio > DesignRatio){
    	scale = height / (width / DesignRatio);
    }else if(ratio < DesignRatio){
    	scale = width / (height * DesignRatio);
    }else{
    	scale = 1;
    }

    return scale;

}

export default {
    data(){
        return {
        
        }
    },
    computed: {
        scaleWrapStyle(){
            let scale = getScale();
            let scaleStr = `scale(${scale})`;
            return { 'transform': scaleStr, '-webkit-transform': scaleStr };
        }
    },
}
</script>
<style lang="less" scoped>
.scale-wrap{
	width: 100%;
	height:100%;
	display: flex;
	transform-origin: left center;
}
</style>
複製代碼

到此爲止咱們已經實現了對橫屏需求處理的一套方案~

【固然若是你遇到前面這些方案沒法解決的橫屏問題也能夠發出來討論一下。看看有沒有好的辦法去解決。】

最後若是文檔對你有幫助,就給個贊吧~

相關代碼

github.com/taoxhsmile/…

署名

by:Tao

相關文章
相關標籤/搜索