隨着公司知識付費業務的發展,產品發現橫屏展現內容的效果和體驗都要比豎屏要來的好。我也感受確實是這樣的~。剛接到這個需求的時候,稍微想了一下,橫屏這還不簡單直接把整個頁面旋轉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>
複製代碼
到此爲止咱們已經實現了對橫屏需求處理的一套方案~
最後若是文檔對你有幫助,就給個贊吧~
by:Tao