🌟前言
目前前端实现移动端适配方案千千万,眼花缭乱各有有缺,但目前来说postcss-px-to-vewiport是一种非常合适的实现方案,postcss-px-to-vewiport是一个基于postCss开发的插件,其原理就是将项目中的px单位转换为vw(视口宽度)。对postCss不了解的朋友可以看看我的上篇文章postCss基本介绍。
🌟实现
本篇文章是使用vite + vue3 基于postCss来实现postcss-px-to-vewiport插件。
1.创建项目
使用vite创建
npm init vite@latest
使用vue脚手架创建
vue create projectname
选自己喜欢的方式创建就OK
2.简单布局
在公司项目开发中,UI会出设计图,会有一个设计稿的宽度,然后我们根据这个宽度去适配,假设我们现在设计稿的宽度是1280,那么我们写出下面的简单布局:
App.vue文件:
<template>
<div class="page">
<div class="left"></div>
<div class="right">
测试自适应
</div>
</div>
</template>
<style scoped>
.page{
width: 1276px;
height: 748px;
display: flex;
border: 2px red solid;
.left{
width: 600px;
height: 300px;
background-color: cadetblue;
}
.right{
width: 300px;
height: 300px;
margin-left: 200px;
background-color: #425e5e;
font-size: 20px;;
}
}
</style>
可以看到,当页面宽度是1280时,我们上面写的代码是没有问题的,那这时候我们修改页面大小效果如下:
明显不是我们想要的效果,那么开搞。
3.编写插件
vite中是自带postCss的,我们不需要额外安装,在vite.config.ts文件中如下:
export default defineConfig({
plugins: [vue()],
server: {
host: '0.0.0.0', //默认情况是不能用ip访问
port: 3000
},
css: {
postcss: {
plugins: []
}
}
})
plugins数组中就是填写需要使用的插件。下面我们编辑pxtoVewiport方法:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {Plugin} from 'postcss'
const pxtoVewiport = (): Plugin => {
return {
postcssPlugin:'pxtoVewiport',
Declaration(node){
const value = node.value
console.log('样式值:',value)
}
}
}
export default defineConfig({
plugins: [vue()],
server: {
host: '0.0.0.0', //默认情况是不能用ip访问
port: 3000
},
css: {
postcss: {
plugins: [pxtoVewiport()]
}
}
})
此时可以看到打印的信息:
也就是说我们已经拿到项目中的所有样式值,那么接下来我们就是要把所有px单位改成vw。
这里我原本自己写正则实现后,发现还会有margin: 20px 60px;这样的情况,裂开,正则太烧脑,使用程序员必备技能,CV大法,看看postcss-px-to-vewiport源码是怎么实现的,然后就拿到了这个正则:
'"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)'
ok,能用就行,那接下来就是替换过程:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {Plugin} from 'postcss'
const getUnitRegexp = (unit: string) => {
return new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + unit, 'g');
}
const pxtoVewiport = (): Plugin => {
return {
postcssPlugin:'pxtoVewiport',
Declaration(node){
const value = node.value
if (value.includes('px')) {
const pxRegexp = getUnitRegexp('px')
node.value = node.value.replace(pxRegexp, (match) => {
return match.replace(/(\d*\.?\d+)/g, (m) => {
return (parseFloat(m) / 1280 * 100).toFixed(3) + 'vw'
})
})
let reg = new RegExp(/px/,'ig') //在这儿把px删掉
node.value = node.value.replace(reg,'')
}
}
}
}
export default defineConfig({
plugins: [vue()],
server: {
host: '0.0.0.0', //默认情况是不能用ip访问
port: 3000
},
css: {
postcss: {
plugins: [pxtoVewiport()]
}
}
})
跑起项目:
这时候单位都转换成了vw,在各种大小的屏幕都是我们想看到的效果了。
继续看代码
这里的1280就是我们开发中的设计稿宽度,3是保留的位数。那么继续优化一下,将设计稿宽带和保留位数改为可传参数:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {Plugin} from 'postcss'
const getUnitRegexp = (unit: string) => {
return new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + unit, 'g');
}
const pxtoVewiport = (viewportSize = 375,Places = 2): Plugin => {
return {
postcssPlugin:'pxtoVewiport',
Declaration(node){
const value = node.value
if (value.includes('px')) {
const pxRegexp = getUnitRegexp('px')
node.value = node.value.replace(pxRegexp, (match) => {
return match.replace(/(\d*\.?\d+)/g, (m) => {
return (parseFloat(m) / viewportSize * 100).toFixed(Places) + 'vw'
})
})
let reg = new RegExp(/px/,'ig') //在这儿把px删掉
node.value = node.value.replace(reg,'')
}
}
}
}
export default defineConfig({
plugins: [vue()],
server: {
host: '0.0.0.0', //默认情况是不能用ip访问
port: 3000
},
css: {
postcss: {
plugins: [pxtoVewiport(1280,3)]
}
}
})
到里就完成了一个移动端适配的小插件。
🌟总结
基于postCss还可以做很多事情,postCss就是css界的babel,我们这里也是基本实现了postcss-px-to-vewiport插件的功能。后续还可以继续改进。