適用框架:Vue2/Vue3
適用設備:pc端/移動端
適配策略:動態rem+動態scale
方案效果:可讓頁面在不同屏幕下、放大縮小時保持頁面不變形
效果示例:
當屏幕變化時:
當放大縮小時:
安裝(屏幕適配插件)
npm i screen-adapter-plugin
適配寫法(推薦):
- 寫class樣式時,使用px單位,class內的px單位編譯後會轉成rem;內聯樣式需要用px函數
px(12)轉為rem,px函數已經掛載在Vue的this上。 - 若想讓class樣式不被轉為rem,可使用
.norem-開頭的class名稱,其大括號範圍內所有樣式不會被轉為rem,或使用大寫的PX單位(需要按文檔配置postcss.plugin) - rem只隨視口的寬度動態調節,若想讓元素高度隨視口高度變化,可使用
vh、%或其他單位 -
內部無法轉為rem的插件,例如echarts、relation-graph等,可在元素上綁定
v-scale。v-scale適合內部沒有rem單位的元素,通過transform的scale屬性讓該元素寬高隨視口的寬度自適應。它還可以傳入一個監聽函數,第一個參數為綁定該指令的元素dom,第二個參數為該元素被放大的倍數,其在視口變化時會自動執行
// 使用方法一,例如echarts元素 <div ref="echartsRef" style="width: 500px;height: 400px;" v-scale></div> // 使用方法二,傳入監聽函數 <div ref="echartsRef" style="width: 500px;height: 400px;" v-scale=="handlerAdaptScale"></div> methods: { handlerAdaptScale(el, scale) { // do sth... }, }
typescript註解:
// px函數註解,可轉換為rem,或在第二個入參傳入true,獲得動態number類型的px
type PX = (px: number, real: boolean) => string | number
// Vue.use時傳入的options
interface InstallOptions {
rootValue: number
}
// 插件提供的方法
interface ScreenAdapter {
rootFontSize: number // 根元素上動態的font-size
init(): void // Vue.use時會自動調用,初始化適配策略
destroy(): void // 銷燬適配策略
getScale(): number // 獲得v-scale被放大縮小的倍數
addListener(callback: Function): void // 添加屏幕變化時的監聽函數
removeListener(callback: Function): void // 移除屏幕變化時的監聽函數
px: PX
}
項目配置
// index.html (防止h5端用户手動放大縮小)
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=no;" />
// package.json 安裝postcss-plugin-px2rem
"devDependencies": {
"postcss-plugin-px2rem": "^0.8.1",
}
// 配置px2rem
// postcss.config.js 寫法
module.exports = {
plugins: {
'postcss-plugin-px2rem': {
rootValue: 192, // 設計稿寬度 / 10
propList: ["*"],
unitPrecision: 5,
selectorBlackList: [/.norem-.*/], // 開頭為.norem-的class的大括號範圍內所有樣式不會被轉為rem
ignoreIdentifier: false,
replace: true,
mediaQuery: false,
},
},
}
// 或者vite.config.js 寫法
export default defineConfig({
css: {
postcss: {
plugins: [
px2rem({
rootValue: 192, // 設計稿寬度 / 10
propList: ["*"],
unitPrecision: 5,
selectorBlackList: [/.norem-.*/], // 開頭為.norem-的class的大括號範圍內所有樣式不會被轉為rem
ignoreIdentifier: false,
replace: true,
mediaQuery: false,
}),
]
}
},
})
// main.js
import screenAdapter from 'screen-adapter'
Vue.use(screenAdapter, {rootValue: 192}) // 掛載screenAdapter類,傳入跟px2rem插件一致的rootValue
// 調用方式
window.screenAdapter
this.screenAdapter
this.px(_,?_)
// 自定義指令使用方式
v-scale
v-scale="handlerAdaptScale"
常見問題
-
放大縮小過程中,有個別元素變形?
- 寫內聯樣式時,未使用px函數包裹,另外有些組件例如el-table-column的寬度只支持傳入px單位的數值,不支持傳入rem,可使用px函數
px(12, true),將第二個參數設置為true,此時會根據屏幕大小傳入動態的px數值 - 設置父元素
line-height:0或者font-size:0 - 內部無法轉化為rem的組件,例如Echarts,可使用
v-scale指令
- 寫內聯樣式時,未使用px函數包裹,另外有些組件例如el-table-column的寬度只支持傳入px單位的數值,不支持傳入rem,可使用px函數
-
文字邊緣模糊?
- 可以增加css
text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-smooth: always;或者font-weight: bold;但效果有限
- 可以增加css
-
Echarts圖表樣式邊緣模糊?
- 使用svg渲染器
echarts.init(this.$refs.chart, null, { renderer: "svg" })
- 使用svg渲染器
-
使用
v-scale時會有留白或溢出?-
v-scale根據視口的寬度縮放元素。如果父元素使用的vh、%這種視口單位,當視口的寬高比小於元素的寬高比,父級元素就會有留白;當父級元素大於元素的寬高比,元素就會有溢出。- 這些情況可把v-scale提升到上面父級
- 內部樣式使用不會被轉為rem的寫法
適配完讓整個頁面的底部留白或溢出產生滾動條,這是正常的。
如果確實不想存在留白或滾動,想要高度也自適應的頁面,可以為元素綁定key值,視口變化時讓其重新渲染:
<template> <div v-scale :key="scaleKey"></div> </template> import { debounce } from "lodash"; export default { data() { return { scaleKey: 1, } }, created() { // 視口變化時讓元素重新綁定v-scale this.screenAdapter.addListener(this.debounceRefreshHeightScale); }, beforeDestroy() { this.screenAdapter.removeListener(this.debounceRefreshHeightScale); }, methods: { debounceRefreshHeightScale: debounce(function () { this.scaleKey++; }, 500), } }此方法比較耗費性能,請謹慎使用!
-
-
使用v-scale的元素寬高顯示有問題?
- 如果使用v-scale的元素的寬高使用的百分比,圖表就有可能在屏幕變化時因為渲染時機問題獲得錯誤的寬高,此時可以使用真px值
<Echarts width="400px" height="300px"/>讓其固定寬高,或用v-if綁定接口的數據來源<Echarts v-if="data.length > 0"/>讓其滯後渲染
- 如果使用v-scale的元素的寬高使用的百分比,圖表就有可能在屏幕變化時因為渲染時機問題獲得錯誤的寬高,此時可以使用真px值
-
VScode強制將大寫PX轉為小寫px
- 在VScode中使用
Vue-official插件,並將其選為默認格式化配置,就不會格式化PX了
- 在VScode中使用
-
為什麼設計時不讓元素隨視口高度縮放?
- 現在所有視圖設計的基本特點就是內容過多時產生垂直滾動條,並且用户天生有向下滾動的直覺,另外瀏覽器也並未提供可以一直準確有效的拿到視口高度的方法,如果想隨視口高度適應,可自行使用
vh、%或其他寫法滿足需要。
- 現在所有視圖設計的基本特點就是內容過多時產生垂直滾動條,並且用户天生有向下滾動的直覺,另外瀏覽器也並未提供可以一直準確有效的拿到視口高度的方法,如果想隨視口高度適應,可自行使用