小知识总结1

判断当前设备是否为移动设备

  1. 如下所示,如果是,则isMobile为true,否则为false

    //写法一:
    const isMobile = /Mobi|Android|iPhone/i.test(navigator.userAgent)
    //写法二:
    const isMobile = navigator.userAgent.match(/Mobi/i) || navigator.userAgent.match(/Android/i)||navigator.userAgent.match(/iPhone/i)

vite项目中判断开发环境和生产环境

  1. 新建.env文件,env后面代表环境类型

    env文件

  2. 内部配置环境

    dev

    prod

    test

    ut

  3. 此时在vue文件中可以通过import.meta.env.VITE_CONFIG进行环境类型的判定,不同环境运用不同的地址

  4. package.json中build命令中进行配置.

    package.json

vite+vue项目的移动端适配

  1. 安装插件

    npm i amfe-flexible
    npm i autoprefixer
    npm i postcss-pxtorem
  2. vite.config.js配置

    import autoprefixer from 'autoprefixer';
    import postCssPxToRem from 'postcss-pxtorem';

    export default defineConfig(({ command, mode }) => {
    return {
    css: {
    postcss: {
    plugins: [
    autoprefixer({
    overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'],
    }),
    postCssPxToRem({
    // 自适应,px>rem转换
    rootValue: 37.5, // 75表示750设计稿,37.5表示375设计稿
    propList: ['*'], // 需要转换的属性,这里选择全部都进行转换
    selectorBlackList: ['norem'], // 过滤掉norem-开头的class,不进行rem转换
    }),
    ],

    }
    },
    }
  3. ok,成功配置,之后根据设计稿的UI,是多少呢px就写多少px,之后会自动转换成rem适配移动端,如果有些单位不想被转换,则将px写为大写即可

  4. 原理

vue3中reactive变量失效问题

  1. 在vue3中响应式数据通过ref或者reactive进行定义,但是对于reactive定义的数据,对其进行赋值时会丢失响应式,目前还未去了解原因,但是丢失响应式是真实存在的

    let infoList = reactive({})

    const testFunction = async () => {
    let result = await .....异步请求
    infoList = result.data //此时infoList就不是响应式数据了
    }
  2. 解决方法

    1. 第一种:使用ref

      let infoList = ref({})

      const testFunction = async () => {
      let result = await .....异步请求
      infoList.value = result.data //此时infoList还是想响应式数据
      }
    2. 第二种:使用嵌套

      let infoList = reactive({
      data:{}
      })

      const testFunction = async () => {
      let result = await .....异步请求
      infoList.data = result.data //此时infoList还是想响应式数据
      }

vue3移动端开发页面跳转动画

  1. Vue3新增<transtion></transtion>标签直接配置页面动画,通过name配置动画名称,如果name是slide,则动画类名为slide-enter-active/slide-enter-to/slide-enter-fromslide-leave-active/slide-leave-to/slide-leave-from

    <transition :name="transitionName">
    <div :key="$route.fullPath" class="all">
    //固定写法
    <router-view v-slot="{ Component }" >
    <keep-alive>
    <component :is="Component" v-if="$route.meta.keepAlive" />
    </keep-alive>
    <component :is="Component" v-if="!$route.meta.keepAlive" />
    </router-view>
    </div>
    </transition>
  2. 动态判断动画名称,通过配置路由的meta属性的index进行判断左滑还是右滑

    let transitionName = ref();
    router.beforeEach((to, from) => {
    console.log(to, from, 'to from ');
    // 根据路由标记判断触发哪个动画
    if (to.meta.index > from.meta.index) {
    // 从右往左动画
    transitionName.value = 'slide-right';
    } else if (to.meta.index < from.meta.index) {
    // 从左往右动画
    transitionName.value = 'slide-left';
    } else {
    transitionName.value = '';
    }
    });
  3. 动画css


    .all {
    height: 100%;
    width: 100%;
    }
    .slide-left-enter-active,
    .slide-left-leave-active,
    .slide-right-enter-active,
    .slide-right-leave-active {
    transition: transform 0.3s;
    }
    .slide-left-leave-active , .slide-right-leave-active {
    position:absolute;
    z-index: -1 !important;
    }

    .slide-right-enter-from {
    transform: translateX(100%);
    }
    .slide-right-enter-to {
    transform: translateX(0);
    }
    .slide-right-leave-from {
    transform: translateX(0);
    }
    .slide-right-leave-to {
    transform: translateX(-100%);
    }

    .slide-left-enter-from {
    transform: translateX(-100%);
    }
    .slide-left-enter-to {
    transform: translateX(0);
    }
    .slide-left-leave-from {
    transform: translateX(0);
    }
    .slide-left-leave-to {
    transform: translateX(100%);
    }
  4. 注意:

    1. transition标签下的div是必要的,不然会报警告Transition包裹的必须是一个单根的组件。
    2. div标签得添id,帮助识别页面是否切换

Vue3关于父子传值遇到的问题

  1. 之前开发项目封装子组件,通过props进行传值,由于之前对于props的使用是一次性的,也就是说props的值不会改变,在子组件中使用方式是下面这样.

    const {data1 , data2} = defineProps({
    data1:String,
    data2:String
    })
  2. 在一次需要对父组件传过来的值进行监听时,只有第一次值可以监听到,之后就监听不到,找了半天也没发现问题,最后在看pinia时发现下面这句话.对props解构会失去响应式,之后将解构赋值去掉后,问题完美解决.

    pinia

    const props = defineProps({
    data1:String,
    data2:String
    })
    //通过props.data1,props.data2进行使用

base64展示以及base64转file

  1. 在开发时,使用相机拍的照片为base64,如果要在页面上展示,则使用data:image/png;base64,+base64

  2. 有些接口上传图片需要图片格式为file,所以将base64转为file,使用下面代码,使用方式如下:

    function base64ImgtoFile(dataurl, filename = 'file') {
    const arr = dataurl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const suffix = mime.split('/')[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], `${filename}.${suffix}`, {
    type: mime,
    });
    }
    let url = 'data:image/png;base64,'+base64
    let file = base64ImgtoFile(url)

倒计时走字过快

  1. 在写一个倒计时组件时,出现问题:第二次倒计时时,走字速度为原来的两倍.第三次速度则是三倍,代码如下

    秒表计时

  2. 原因: 每次进来都是新的一个timer,所以clear的也是新的,而不是之前的timer,导致每点击一次速度加快一倍

  3. 解决方法:将timer定义为全局变量

图片打包加载不到问题

  1. 在进行图标引入时,如果想要循环渲染图片,需要先定义变量,再使用,类似下面这样

    <script>
    //定义
    let obj = ref([
    {
    name:"xx",
    icon:'@/assets/a.png'
    },
    {
    name:"xxx",
    icon:'@/assets/b.png'
    },
    {
    name:"xxxx",
    icon:'@/assets/c.png'
    },
    {
    name:"xxxxx",
    icon:'@/assets/d.png'
    },
    ])
    </script>

    <template>
    <div v-for=(value , index) in obj :key = 'index'>
    <img :src="value.icon"/>
    <div>{{value.name}}</div>
    </div>
    </template>
  2. 但是上面的这种情况会导致问题:由于定义的时候写的是相对路径,所以打包后找不到图片地址

  3. 解决方法:使用import引入

    import xx from '@/assets/xx.png'

ios搜索框失焦

  1. 在进行移动端开发时,由于ios的搜索框在聚焦后除了点击键盘上的收回键,并不会自动收起键盘,导致ios在配置了防遮挡后,可以一直往上滑.

  2. 解决方法:当点击区域不再搜索框,就手动失焦(虽然实现简单,但是当时没有这个思路)

    const handleClickOutside = (e) => {
    if(e.target.className!= 'van-field__control'){
    // 当前点击的元素不是输入框,收起键盘
    document.activeElement.blur();
    }
    };

    <div class="container" @click="handleClickOutside">
    <van-search
    ref="searchInput"
    v-model="searchValue.name"
    shape="round"
    placeholder="订单号/投保人姓名"
    :clearable="false"
    autofocus
    @keydown="confirmSearch">
    </van-search>
    </div>

viewport-fit=cover

  • ios沉浸式状态栏配置项

Vue3样式中使用js变量以及样式穿透

  1. 样式中的变量使用

    let height = ref('12px')

    <style>
    .container {
    height:v-bind(height)
    }
    <style>
  2. 样式穿透

    • 方式一

      ::v-deep(.className) {}
    • 方式二

      :deep(.className){}

van-field ios输入框兼容性问题

  1. 问题描述:输入框使用input做了规则校验,如下所示,当每次input都会调用该方法,这样当在ios上用中文拼音输入时,会导致每次输入都会把前面所输入的再复制一遍.

    const handleInputClineName = (e) => {
    const pattern = /[^\u4e00-\u9fa5a-zA-Z]/g;
    e.target.value = e.target.value.replace(pattern, "");
    clientName.value = e.target.value
    }
  2. 解决方法:js中有两个事件compositionstartcompositionend 第一个是当用户使用拼音开始输入汉字时触发,第二个方法为用户输入完毕后触发,所以可以在用户输入结束后再赋值。

    //输入结束后校验
    const compositionend = (e) => {
    const pattern = /[^\u4e00-\u9fa5a-zA-Z]/g;
    e.target.value = e.target.value.replace(pattern, "");
    clientName.value = e.target.value
    }
    //每次输入时校验
    const handleInputClineName = (e) => {
    const pattern = /[^\u4e00-\u9fa5a-zA-Z]/g;
    clientName.value = clientName.value.replace(pattern, "");
    }
  3. ios产生原因:ios输入拼音,拼音会展示出来,触发input事件,再次点击拼音就会导致复制前面输入的拼音,Android中每次拼音输入并不会触发input事件。

rollup-plugin-visualizer

  1. vite打包费时可视化插件,根据花费时间优化打包时间

  2. 使用

    • npm i rollup-plugin-visualizer -D

    • vite.config.js中配置

      1. 引入

        import { visualizer } from "rollup-plugin-visualizer";
      2. 在plugins配置项中进行配置

        visualizer({
        open:true, //注意这里要设置为true,否则无效
        filename: "stats.html", //分析图生成的文件名
        gzipSize: true, // 收集 gzip 大小并将其显示
        brotliSize: true, // 收集 brotli 大小并将其显示
        })
  3. 在打包后会生成stats.html文件,该文件在浏览器中打开如图所示,鼠标放到每一块上即可展示文件目录以及打包费时。

    打包结果图

user-select

  • 使用div写一些用户可以点击的按钮时会导致用户可以复制按钮,这是不合理的,通过在该div上添加user-select:none来禁止用户复制

ios上的数字被识别为电话号码

  1. 问题:ios上的一些数字串会被识别为电话号码,导致其展示为蓝色,
  2. 解决方法:<meta name="format-detection" content="telephone=no" />

ios上fixed定位抖动

  1. 之前在实现ios沉浸式时,设置viewport-fit=cover属性,实现了沉浸式,但是底部会出现高度等同于状态栏的白条。
  2. 为了解决白条问题在body上添加了属性height:100vh,解决了白条问题
  3. 但是使用100vh后导致一些fixed定位元素在页面切换时出现抖动问题
  4. 解决方法:网上解决ios fixed定位抖动问题的方法很多,像添加transform: translateZ(0),或者固定定位外使用绝对定位进行包裹等等,但是试了一下都没用。最后在body上添加posittion:relative解决

设置主题样式全局通用

  1. 项目内容大致相同,主题色不同时使用

  2. 全局scss中使用

    1. 添加样式文件theme.scss

      $themeColor:#5a90f7; //主题色
      $themeTextColor:#203154;//字体色
    2. vite.config.js中配置

      css: {
      preprocessorOptions: {
      scss: {
      additionalData: '@import "./src/style/theme.scss";',//文件路径
      javascriptEnabled:true
      }
      }
    3. 之后可以在任意文件中访问$themeColor $themeTextColor

  3. 全局js中使用

    1. 添加样式文件theme.module.scss

      $themeColor:#5a90f7; //主题色
      $themeTextColor:#203154;//字体色

      :export {
      themeColor:$themeColor;
      themeTextColor:$themeTextColor;
      }
    2. 直接在需要使用的地方引入

      import theme from '@/style/theme.module.scss'
      console.log(theme)

      theme输出

关闭git对于文件名大小写变化的忽视

git config core.ignorecase false

移动端禁止页面左滑返回

  1. 添加backbutton事件监听

    document.addEventListener("backbutton",handler);
    const handler = (e) => {
    e.preventDefault();
    }
  2. 只要添加了监听之后,页面就不能在使用滑动返回,无论是否执行 *e.preventDefault()*,比如下面这种,无论a是否等于b,都不能通过手势进行返回。

    document.addEventListener("backbutton",handler);
    const handler = (e) => {
    if(a === b) {
    e.preventDefault();
    }
    }
  3. 所以想要可以滑动返回,需要在指定位置进行移除监听

    document.removeEventListener('backbutton',handler)

在 Vue 3 中,onMounted 钩子函数默认是不支持 async/await 的

Author: Yang Wa
Link: https://blog.wxywxy.cn/2023/07/18/小知识总结/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.