淺析微信小程序響應式像素實現原理
本次分享我們來談談微信小程序的響應式像素是如何實現的。
官方文檔說明
WXSS (WeiXin Style Sheets)是一套樣式語言,用于描述 WXML 的組件樣式。
WXSS 用來決定 WXML 的組件應該怎么顯示。
為了適應廣大的前端開發者,WXSS 具有 CSS 大部分特性。同時為了更適合開發微信小程序,WXSS 對 CSS 進行了擴充以及修改。
尺寸單位
rpx(responsive pixel): 可以根據屏幕寬度進行自適應。規定屏幕寬為750rpx。如在 iPhone6 上,屏幕寬度為375px,共有750個物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
那么在 iPhone6 的環境下,為什么寫了2rpx就會等同于1px呢?
帶著疑問我們可以在解包之后的文件中找到答案。
首先如果你讀過博主前面的文章,應該會知道小程序的本質是一個混合應用,是一堆js代碼,頁面結構及業務邏輯都是打包為js的,然后wxss樣式本身也是用服務端的編譯器去打包為js的,所以我們就可以從源碼上略知一二了。
如果你試著去尋找一下,會發現類似如下的代碼。
這里我們節選一部分代碼來幫助理解所謂響應式像素的實現過程。
var BASE_DEVICE_WIDTH = 750; var isIOS = navigator.userAgent.match('iPhone'); var deviceWidth = window.screen.width || 375; var deviceDPR = window.devicePixelRatio || 2; var checkDeviceWidth = window.__checkDeviceWidth__ || function () { var newDeviceWidth = window.screen.width || 375; var newDeviceDPR = window.devicePixelRatio || 2; var newDeviceHeight = window.screen.height || 375; if ( window.screen.orientation && /^landscape/.test(window.screen.orientation.type || '') ) newDeviceWidth = newDeviceHeight; if (newDeviceWidth !== deviceWidth || newDeviceDPR !== deviceDPR) { deviceWidth = newDeviceWidth; deviceDPR = newDeviceDPR; } }; checkDeviceWidth(); var eps = 1e-4; var transformRPX = window.__transformRpx__ || function (number, newDeviceWidth) { if (number === 0) return 0; number = (number / BASE_DEVICE_WIDTH) * (newDeviceWidth || deviceWidth); number = Math.floor(number + eps); if (number === 0) { if (deviceDPR === 1 || !isIOS) { return 1; } else { return 0.5; } } return number; };
下面我們來一起看下吧~
小程序頁面在注冊的過程中會定義一些變量:
BASE_DEVICE_WIDTH,值為750,也就是官網所說的基準設備寬度(規定屏幕寬為750rpx)。
deviceWidth,取值為屏幕寬度,默認值375。
deviceDPR,設備上物理像素和邏輯像素的比例,所說的像素密度,默認為2。
另外通過用戶代理(UA)來判斷設備是否為IOS,之后定義了一個全局變量checkDeviceWidth指向的一個掛載在window對象下全局函數__checkDeviceWidth__,如果window下面沒這個對象則直接返回一段檢查屏幕寬高的函數。如果是橫屏情況則會把屏幕寬度設為高度值,重新設置寬高。
之后直接執行了這段函數checkDeviceWidth。
再往下就是本次的關鍵部分了,定義了一個名為transformRPX的函數,看意思就知道了,作用是轉化rpx單位的,該函數支持傳入兩個參數:
number
newDeviceWidth
這里大家應該明白了,傳入的第一個參數就是我們手寫的wxss樣式某標簽的具體寬高值,第二個則是設備寬度。
函數內容也大致說下吧:
如果傳的是0,比如0rpx,那轉換之后自然就是0了
如果不是 0,則按公式((number / BASE_DEVICE_WIDTH) * (newDeviceWidth || deviceWidth))做了換算,就是按照傳入值與基準設備寬度得到的比率乘以當前設備寬度
并且這里利用1e-4的eps值做了小量比較,即傳入的number值轉換之后加上eps并向下取整了。
并且取整之后為0的情況,如果像素密度為1或者是非IOS設備則返回1,像素密度如果大的,或者IOS的設備就返回了0.5。
大致的作用就解析到這里吧,頁面樣式最終轉換后還是以px為單位進行渲染的。
所以會有同學又有疑問了,小程序運行環境中的webview下面到底認不識rpx呢?
這里其實大家應該大概了解微信小程序的是如何根據屏幕寬度進行自適應顯示的思路了。
當然這里只是簡要介紹了一下,真實情況要比這個復雜,我們從視圖層基礎庫的代碼中也可以窺探到一些有意思的東西,比如組件占位符的樣式,內聯樣式的轉換等等(有興趣的同學可以試著在基礎庫的 WAWebview.js 文件中去搜索一下 transformRpx)。
參考資料
wxss(https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxss.html)
Math.floor()(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/floor)
使用 epsilon 比較浮點數(https://www.zhihu.com/question/37207811)
iOS 小程序
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。