vue【移動(dòng)端適配】

主角是誰

在今天這篇文章中,我并不會(huì)在這里講一些移動(dòng)端視口的概念,包括物理像素和邏輯像素,理想視口,dpr等等等等,我只介紹這樣一種非常不錯(cuò)的移動(dòng)端適配方案:post-css-to-viewport

痛點(diǎn)在哪里

在之前有一種流行已久的移動(dòng)端適配方案,那就是rem,我想下面這兩句代碼,有不少老移動(dòng)端都不會(huì)陌生:

const deviceWidth = document.documentElement.clientWidth || document.body.clientWidth; 
document.querySelector('html').style.fontSize = deviceWidth / 7.5 + 'px';

沒錯(cuò),在那個(gè)移動(dòng)端UI稿尺寸為750*1334滿天飛的時(shí)代,這兩句代碼確實(shí)給開發(fā)者帶來了很大的方便,這樣設(shè)置根font-size后,px和rem的轉(zhuǎn)換比例成了100, 為比如UI稿一個(gè)長(zhǎng)寬分別為120px*40px,那么開發(fā)者對(duì)應(yīng)的寫成1.2rem*0.4rem就可以了

這種換算已經(jīng)是頗為方便,但是并非所有的項(xiàng)目都能這樣去設(shè)置一個(gè)方便換算的比例系數(shù),當(dāng)比例系數(shù)為100時(shí),小數(shù)點(diǎn)往前面挪兩位就行了,然而有的項(xiàng)目設(shè)置的換算系數(shù)千奇百怪,有50的,有16的,很多已經(jīng)嚴(yán)重超出口算力所能及的范疇了。所以后來誕生的px-to-rem或者px2rem就是為了解決這個(gè)問題

人們希望有這樣一種方案...

  • 首先,無論換算方不方便,我都不想換算(就是這么懶??),我也不想去操心什么轉(zhuǎn)換系數(shù)
  • 其次,有些屬性或者類選擇器我不想進(jìn)行轉(zhuǎn)換
  • css代碼要足夠簡(jiǎn)潔,我只希望看到一種單位,那就是px

兩種方案都很好,但我偏愛后者

第一種方案是lib-flexible+postcss-pxtorem,在相當(dāng)長(zhǎng)一段時(shí)間里,這兩個(gè)插件搭配都是解決移動(dòng)端布局的神器,lib-flexible是阿里手淘系開源的一個(gè)庫(kù),用于設(shè)置font-size,同時(shí)處理一些窗口縮放的問題。其中一位主要貢獻(xiàn)者正是阿里的大神winter。

直到2020年的今天,我仍然可以說,lib-flexible+postcss-pxtorem是解決移動(dòng)端布局的主流,但是我們可以好好想一想,它是否有什么不足?

從我個(gè)人來說,我認(rèn)為它主要有以下兩個(gè)不足:

  1. 兩個(gè)插件需要配套使用,而且rootValue設(shè)置的值不好理解
  2. rem是相對(duì)于html元素字體單位的一個(gè)相對(duì)單位,從本質(zhì)上來說,
    它屬于一個(gè)字體單位,用字體單位來布局,并不是太合適

翻閱其github地址,可以看到這樣一段有意思的話:


707643868f2e35ee7e1cac9b9439c04b.png

第二種方案是viewport,postcss-px-to-viewport就是這樣一款優(yōu)秀的插件,它解決了以上提到的痛點(diǎn),也滿足以上提到的理想要求。它將px轉(zhuǎn)換成視口單位vw,眾所周知,vw本質(zhì)上還是一種百分比單位,100vw即等于100%,即window.innerWidth

在vue項(xiàng)目中引入試試

  1. 我們先把它安裝到項(xiàng)目的開發(fā)環(huán)境中:
 npm i postcss-px-to-viewport -D
  1. 在項(xiàng)目根目錄下添加.postcssrc.js文件
  2. 添加如下配置:
module.exports = {
  plugins: {
    autoprefixer: {}, // 用來給不同的瀏覽器自動(dòng)添加相應(yīng)前綴,如-webkit-,-moz-等等
    "postcss-px-to-viewport": {
      unitToConvert: "px", // 要轉(zhuǎn)化的單位
      viewportWidth: 750, // UI設(shè)計(jì)稿的寬度
      unitPrecision: 6, // 轉(zhuǎn)換后的精度,即小數(shù)點(diǎn)位數(shù)
      propList: ["*"], // 指定轉(zhuǎn)換的css屬性的單位,*代表全部css屬性的單位都進(jìn)行轉(zhuǎn)換
      viewportUnit: "vw", // 指定需要轉(zhuǎn)換成的視窗單位,默認(rèn)vw
      fontViewportUnit: "vw", // 指定字體需要轉(zhuǎn)換成的視窗單位,默認(rèn)vw
      selectorBlackList: ["wrap"], // 指定不轉(zhuǎn)換為視窗單位的類名,
      minPixelValue: 1, // 默認(rèn)值1,小于或等于1px則不進(jìn)行轉(zhuǎn)換
      mediaQuery: true, // 是否在媒體查詢的css代碼中也進(jìn)行轉(zhuǎn)換,默認(rèn)false
      replace: true, // 是否轉(zhuǎn)換后直接更換屬性值
      exclude: [/node_modules/], // 設(shè)置忽略文件,用正則做目錄名匹配
      landscape: false // 是否處理橫屏情況
    }
  }
};
  1. 重新運(yùn)行項(xiàng)目,使配置文件生效
  2. 我們寫一段測(cè)試代碼來驗(yàn)證一下:
<template>
  <div class="test-viewport">測(cè)試轉(zhuǎn)換</div>
</template>
 
<style lang="less" scoped>
.test-viewport {
  width: 750px;
  height: 100px;
  font-size: 40px;
  text-align: center;
  line-height: 100px;
  background: #13b5b1;
}
</style>
  1. 打開控制臺(tái),查看是否已經(jīng)進(jìn)行了轉(zhuǎn)換

需要注意的配置

  • propList: 當(dāng)有些屬性的單位我們不希望轉(zhuǎn)換的時(shí)候,可以添加在數(shù)組后面,并在前面加上!號(hào),如propList: ["*","!letter-spacing"],這表示:所有css屬性的屬性的單位都進(jìn)行轉(zhuǎn)化,除了letter-spacing
  • selectorBlackList:轉(zhuǎn)換的黑名單,在黑名單里面的我們可以寫入字符串,只要類名包含有這個(gè)字符串,就不會(huì)被匹配。比如selectorBlackList: ['wrap'],它表示形如wrap,my-wrap,wrapper這樣的類名的單位,都不會(huì)被轉(zhuǎn)換

關(guān)于兼容第三方UI庫(kù)

當(dāng)然,當(dāng)我們引入一些第三方庫(kù)的時(shí)候,比如vant,上面配置的exclude去掉,表示全部?jī)?nèi)容進(jìn)行vw轉(zhuǎn)換,會(huì)遇到這樣的問題:

d2bfe48ee36b9f8bfa1508b3278b9292.png

像這個(gè)TabBar,變得非常的小,被壓扁了。

其實(shí)vant官網(wǎng)也是給出了關(guān)于viewport的適配方案,在github找一個(gè)名為vant-demo的項(xiàng)目,可以看到其配置如下:


8cb7ea3da517a394339357fe87142281.png

很尷尬,vant團(tuán)隊(duì)的是根據(jù)375px的設(shè)計(jì)稿去做的,理想視口寬度為375px。

那么,我們是否也要叫UI重新出一版375px的設(shè)計(jì)稿?

或者,我們?cè)跁鴮懙倪^程心算一下,所有標(biāo)注的尺寸都除以2?

讓我們回到webpack本身,重新看一下這份.postcssrc.js文件,它除了暴露一個(gè)對(duì)象,也可以暴露一個(gè)函數(shù),無論暴露什么,在webpack運(yùn)行時(shí),都會(huì)被我們配置的海量文件讀取并執(zhí)行。

暴露函數(shù)有一個(gè)好處,可以拿到webpack運(yùn)行的當(dāng)前執(zhí)行文件的信息。

那么我們可以有這樣一個(gè)思路:如果讀取的是vant相關(guān)的文件,viewportWidth就設(shè)為375,如果是其他的文件,我們就按照我們UI的寬度來設(shè)置viewportWidth,即750。

改寫.postcssrc.js文件配置如下:

const path = require('path');
 
module.exports = ({ file }) => {
  const designWidth = file.dirname.includes(path.join('node_modules', 'vant')) ? 375 : 750;
 
  return {
    plugins: {
      autoprefixer: {},
      "postcss-px-to-viewport": {
        unitToConvert: "px",
        viewportWidth: designWidth,
        unitPrecision: 6,
        propList: ["*"],
        viewportUnit: "vw",
        fontViewportUnit: "vw",
        selectorBlackList: [],
        minPixelValue: 1,
        mediaQuery: true,
        exclude: [],
        landscape: false
      }
    }
  }
 
}

注意:這里使用path.join('node_modules', 'vant')是因?yàn)檫m應(yīng)不同的操作系統(tǒng),在mac下結(jié)果為node_modules/vant,而在windows下結(jié)果為node_modules\vant

重新運(yùn)行后發(fā)現(xiàn),不僅vant相關(guān)組件的單位被轉(zhuǎn)換成了vw,而且其比例也是完全正確的。


326bd171a43939000509be69e7d1f27b.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容