vue3 开发移动端基础配置

一、移动适配

安装依赖

将px转成vh和vw

npm install postcss-px-to-viewport -D

配置 vite.config.ts

因为vite中已经内联了postcss,所以并不需要额外的创建 postcss.config.js文件

import {
    
     defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import postcsspxtoviewport from "postcss-px-to-viewport"

// https://vitejs.dev/config/
export default defineConfig({
    
    
  plugins: [
    vue(),
    AutoImport({
    
    
      imports: ['vue'],
      dts: "src/auto-import.d.ts"
    })
  ],
  css: {
    
    
    postcss: {
    
    
      plugins: [
        postcsspxtoviewport({
    
    
          unitToConvert: 'px', // 要转化的单位
          viewportWidth: 750, // UI设计稿的宽度
          unitPrecision: 6, // 转换后的精度,即小数点位数
          propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
          viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
          fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
          selectorBlackList: ['ignore-'], // 指定不转换为视窗单位的类名,
          minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
          mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
          replace: true, // 是否转换后直接更换属性值
          landscape: false // 是否处理横屏情况
        })
      ]
    }
  }
})

注意:若需要声明文件则可以复制以下

// postcss-px-to-viewport.d.ts
declare module 'postcss-px-to-viewport' {
    
    
    type Options = {
    
    
        unitToConvert: 'px' | 'rem' | 'cm' | 'em',
        viewportWidth: number,
        viewportHeight: number, // not now used; TODO: need for different units and math for different properties
        unitPrecision: number,
        viewportUnit: string,
        fontViewportUnit: string,  // vmin is more suitable.
        selectorBlackList: string[],
        propList: string[],
        minPixelValue: number,
        mediaQuery: boolean,
        replace: boolean,
        landscape: boolean,
        landscapeUnit: string,
        landscapeWidth: number
    }
    // Partial 将参数变为可选
    export default (options: Partial<Options>) => any
}

引入声明文件postcss-px-to-viewport.d.tsvite.config.ts同级

// tsconfig.json
{
    
    
  "extends": "@vue/tsconfig/tsconfig.web.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "postcss-px-to-viewport.d.ts"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    
    
    "composite": true,
    "baseUrl": ".",
    "paths": {
    
    
      "@/*": ["./src/*"]
    }
  }
}

代码案例

<template>
  <div class="wraps">
    <header>
      <div class="header-left">左边</div>
      <div class="header-middle">中间</div>
      <div class="header-right">右边</div>
    </header>
    <main>
      <div class="main-content" v-for="item in 50">
        <div class="portrait"></div>
        <div class="main-desc">
          <div>名字:{
    
    {
    
     item }}</div>
          <div>介绍:我是{
    
    {
    
     item }},我要回家吃饭了</div>
        </div>
      </div>
    </main>
    <footer>
      <div class="footer-content" v-for="item in footer">
        <div class="footer-icon">{
    
    {
    
     item.icon }}</div>
        <div class="footer-text">{
    
    {
    
     item.text }}</div>
      </div>
    </footer>
  </div>
</template>

<script setup lang='ts'>

type Footer<T> = {
    
    
  icon: T,
  text: T
}
const footer = reactive<Footer<string>[]>([
  {
    
    
    icon: '1',
    text: '首页'
  },
  {
    
    
    icon: '2',
    text: '商品'
  },
  {
    
    
    icon: '3',
    text: '购物车'
  },
  {
    
    
    icon: '4',
    text: '我的'
  }
])

</script>

<style lang='less' scoped>
body,
html,
#app {
    
    
  overflow: hidden;
  height: 100%;
  font-size: 14px;
}

header {
    
    
  display: flex;
  justify-content: space-around;
  padding: 10px;
  background-color: #4c7cf6;
}

main {
    
    
  display: flex;
  flex-direction: column;

  .main-content {
    
    
    flex: 1;
    display: flex;
    padding: 10px;
    border-bottom: 1px solid #ccc;

    .portrait {
    
    
      width: 50px;
      height: 50px;
      border-radius: 50%;
      background-color: #000;
      margin-right: 10px;
    }

    .main-desc {
    
    
      >div:last-child {
    
    
        margin-top: 5px;
        font-size: 12px;
        color: #ccc;
      }
    }
  }
}

footer {
    
    
  // display: grid;
  // grid-template-columns: 1fr 1fr 1fr 1fr;
  border-top: 1px solid #ccc;
  position: fixed;
  bottom: 0;
  display: flex;
  justify-content: space-around;
  width: 100%;
  padding: 10px;
  background-color: #265dc2;

  .footer-content {
    
    
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 5px;
  }
}
</style>

使用vant的ui框架

安装

npm i vant

引入组件

这里使用按需引入
安装插件

npm i unplugin-vue-components -D

基于 vite 的项目,在 vite.config.js 文件中配置插件:

import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import {
    
     VantResolver } from 'unplugin-vue-components/resolvers';

export default {
    
    
  plugins: [
    vue(),
    Components({
    
    
      resolvers: [VantResolver()],
    }),
  ],
};

就可以在页面调用组件了

存在一个问题就是vant的设计尺寸为325px,我们用的postcss-px-to-viewport插件定义的是750px

网上的解决方案有:

方案一
干脆就稍加改了一下postcss-px-to-viewport的代码

其实就是在src/index.js中加入了以下代码,把当前文件路径暴露出去,接收一个新的viewportWidth并赋值给opts

具体可以看下源代码

if(opts.customFun){
    
    
  opts.viewportWidth = opts.customFun({
    
    file:rule.source.input.file});
}

配置时使用cnjm-postcss-px-to-viewport

const path = require("path");
module.exports = () => {
    
    
  return {
    
    
    plugins: {
    
    
      autoprefixer: {
    
    
        overrideBrowserslist: ["Android 4.1", "iOS 7.1", "Chrome > 31", "ff > 31", "ie >= 8"],
      },
      // 修改插件名称
      "cnjm-postcss-px-to-viewport": {
    
    
        unitToConvert: "px", // 要转化的单位
        viewportWidth: 750, // UI设计稿的宽度
        unitPrecision: 6, // 转换后的精度,即小数点位数
        propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
        viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
        fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
        selectorBlackList: ["ignore"], // 指定不转换为视窗单位的类名,
        minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
        mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
        replace: true, // 是否转换后直接更换属性值
        exclude: [], // 设置忽略文件,用正则做目录名匹配
        landscape: false, // 是否处理横屏情况
        // 如果没有使用其他的尺寸来设计,下面这个方法可以不需要,比如vant是375的
        customFun: ({
     
      file }) => {
    
    
          // 这个自定义的方法是针对处理vant组件下的设计稿为375问题
          const designWidth = path.join(file).includes(path.join("node_modules", "vant")) ? 375 : 750;
          return designWidth;
        },
      },
    },
  };
};

方案二
https://github.com/vitejs/vite/issues/4653 多个配置,这将导致插件处理两次,优点缺点都很明显,具体怎么用,见人见智了

const px2viewport = require("postcss-px-to-viewport");
const autoprefixer = require("autoprefixer");
module.exports = () => {
    
    
  return {
    
    
    plugins: [
      autoprefixer({
    
    
        overrideBrowserslist: ["Android 4.1", "iOS 7.1", "Chrome > 31", "ff > 31", "ie >= 8"],
      }),
      px2viewport({
    
    
        unitToConvert: "px", // 要转化的单位
        viewportWidth: 375, // UI设计稿的宽度
        unitPrecision: 6, // 转换后的精度,即小数点位数
        propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
        viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
        fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
        selectorBlackList: ["ignore"], // 指定不转换为视窗单位的类名,
        minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
        mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
        replace: true, // 是否转换后直接更换属性值
        exclude: [/^(?!.*node_modules\/vant)/], // 设置忽略文件,用正则做目录名匹配
        landscape: false, // 是否处理横屏情况
      }),
      px2viewport({
    
    
        unitToConvert: "px", // 要转化的单位
        viewportWidth: 750, // UI设计稿的宽度
        unitPrecision: 6, // 转换后的精度,即小数点位数
        propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
        viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
        fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
        selectorBlackList: ["ignore"], // 指定不转换为视窗单位的类名,
        minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
        mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
        replace: true, // 是否转换后直接更换属性值
        exclude: [/node_modules\/vant/i], // 设置忽略文件,用正则做目录名匹配
        landscape: false, // 是否处理横屏情况
      }),
    ],
  };
};

方案三
直接替换vant :root 下的变量下的数值,没验证过,但想来应该挺麻烦的。

猜你喜欢

转载自blog.csdn.net/weixin_46051479/article/details/127001939