前端随笔记录(个人笔记)

229 阅读5分钟

2021/08/02

1. 退出登录的问题

+ 场景
    - url携带了token,退出登录时,去除url中的参数,并清空路由
+ 解决方法:
    - 点击退出按钮时,this.$router.replace({path: '/login'});  location.reload();  并执行相关的初始化函数
    - 在login页面,检测是否有参数,有则location.replace(location.href.split("?")[0] + "#/login");

2. 替换掉图片src的相对路径的方法

const exchangeUrl = function (txt, reverse = false) {
  if (!reverse) {
    //换掉相对路径的图片
    txt = txt.replace(
      /<img [^>]*src=['"]([^'"]+)[^>]*>/gi,
      function (match, capture) {
        if (capture.includes("./")) {
          let newCapture = capture.replace(
            "./",
            "http://xxxxxxxxxxxxxxxxxxxxxxxxxx"
          );
          match = match.replace(capture, newCapture);
        }
        return match;
      }
    );
  } else {
    //换掉相对路径的图片
    txt = txt.replace(
      /<img [^>]*src=['"]([^'"]+)[^>]*>/gi,
      function (match, capture) {
        if (capture.includes("./")) {
          let newCapture = capture.replace("tiku/", ".");
          match = match.replace(capture, newCapture);
        }
        return match;
      }
    );
  }

  return txt;
};

时间戳转时分秒

timeStr() {
    let { sumSecond } = this;
    let mss = sumSecond * 1000;
    var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    var minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
    var seconds = (mss % (1000 * 60)) / 1000;
    hours = hours <= 9 ? "0" + hours : hours;
    minutes = minutes <= 9 ? "0" + minutes : minutes;
    seconds = seconds <= 9 ? "0" + seconds : seconds;
    if (hours == "00") {
    return `${minutes}:${seconds}`;
    } else {
    return `${hours}:${minutes}:${seconds}`;
    }
},

检测用户关闭浏览器或关闭tab

// 检测的浏览器行为

// 挂载时 定义window的onbeforeunload事件
mounted() {
    let that = this;
    window.onbeforeunload = function (e) {
    // 如果未保存 则有关闭提示 这里的条件你可自己定义
      if (!that.isSave) {
        e = e || window.event;
        // 兼容IE8和Firefox 4之前的版本
        if (e) {
          e.returnValue = "关闭提示";
        }
        // Chrome, Safari, Firefox 4+, Opera 12+ , IE 9+
        return "关闭提示";
      }
    };
  },
// 销毁时 定义window的onbeforeunload事件为null
destroyed() {
    window.onbeforeunload = null;
},

vue检测用户离开时是否保存页面

// 只能检测路由的行为
beforeRouteLeave(to, from, next) {
    if (!this.isSave) {
      next(false);
      let result = confirm("草稿未保存,是否退出?");
      if (result) {
        next();
      }
    } else {
      next();
    }
},

2021/10/12

scss变量全局引入的方法

  • 在vue.config.js中设置
css: {
        loaderOptions: {
            sass: {
                prependData: `@import "@/style/varible.scss";`
            }
        }
    }

2021/10/30

IE与低版本webview不兼容es6导致的白屏

  • 主要设置方法
  • 补充
    • 对于某些采用ES6语法的第三方module 需要再vue.config.js中设置对其进行转译
    • 如下所示 对几个库进行转译
    transpileDependencies: [
        // can be string or regex
        /vue-echarts-v3.src.*?js$/,
        'webpack-dev-server/client',
        /_js-base64.*?/,
        /_@keyrinrin_rtf-util.*?/,
        // '_vconsole@3.7.0@vconsole'
    ],
    

antd-vue按需引入的坑

  • 创建vue项目时,选择的是sass-loader,提示缺少less-loader

    • 需要安装较低版本的less-loader 否则会报错 this.getOptions is not a function
    npm install less-loader@6.0.0
    
  • 报错.bezierEasingMixin()

    • 在vue.config.js中设置
        module.exports = {
            css: {
                loaderOptions: {
                    less: {
                        lessOptions: {
                            javascriptEnabled: true,
                        },
                    },
            },
            },
        }
    

2021/11/24

Vue首屏加载优化

  • 接触到的原因
    • 公司一个项目,首屏加载比较慢,需要优化。
  • 寻找加载慢的原因
    • 通过控制台查看加载的资源情况
  • 资源加载的情况

1.png

  • 分析原因
    • chunk-vendors过大
    • 背景图片过大
  • 解决方法
    • 使用图片压缩工具,减少png大小

    • TinyPNG

    • 3.png

    • vue router设置路由懒加载

    • 2.png

    • 部分首屏用不到的组件,设置其按需导入

    • 3.png

2021/11/30

  • 原笔迹轨迹顺滑还原的方法(利用canvas的贝塞尔曲线)
let t = 0.5; // 曲率参数0-1 经过验证0.5比较合适
/**
    @params points 点数组 
    @params t 曲率参数
**/
function Draw(points, t = 0.5){
    for (var i = 0; i < points.length - 1; i++) {
          ctx.beginPath();
          ctx.moveTo(points[i].x, points[i].y);
          var p0 = (i > 0) ? points[i - 1] : points[0];
          var p1 = points[i];
          var p2 = points[i + 1];
          var p3 = (i != points.length - 2) ? points[i + 2] : p2;
          ctx.lineWidth = (p0.p + p1.p) / 2 * p0.width;
          var cp1x = p1.x + (p2.x - p0.x) / 6 * t;
          var cp1y = p1.y + (p2.y - p0.y) / 6 * t;
          var cp2x = p2.x - (p3.x - p1.x) / 6 * t;
          var cp2y = p2.y - (p3.y - p1.y) / 6 * t;
          ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2.x, p2.y);
          ctx.stroke();
          ctx.closePath();
        }
}

2022/09/29

后端返回buffer, 前端下载文件

return request({
    method: "POST",
    responseType: "blob",
    params: {
     // 相关参数
    },
    data,
  }).then((resp) => {
    let content = resp.headers["content-disposition"];
    let name = content && content.split(";")[1].split("filename=")[1];
    let fileName = decodeURIComponent(name).slice(1, -1);
    var blob = resp.data;
    var downloadElement = document.createElement("a");
    var href = window.URL.createObjectURL(blob);
    downloadElement.href = href;
    downloadElement.download = fileName;
    document.body.appendChild(downloadElement);
    downloadElement.click();
    document.body.removeChild(downloadElement);
    window.URL.revokeObjectURL(href);
  });

2023/09/19

uniApp 开发安卓App相关问题

  1. 扫一扫相机权限
    const scanCode = () => {
            let hasRight = plus.navigator.checkPermission('CAMERA'); // 判断是否授权
            if (hasRight != 'authorized') {
                    // 发起权限请求
                    plus.android.requestPermissions(['android.permission.CAMERA'], (e) => {
                            // 若无相机权限 则提示
                            if (e.granted.length == 0) {
                                    uni.showToast({
                                            title: '无相机权限',
                                            duration: 3000,
                                    })
                            } else {
                                    scanCodeFn();
                            }
                    });
            } else {
                    scanCodeFn();
            }
    };
    const scanCodeFn = () => {
            uni.scanCode({
                    onlyFromCamera: true,
                    success: function(res) {
                            console.log('条码类型:' + res.scanType);
                            console.log('条码内容:' + res.result);
                    },
                    fail: (error) => {
                            console.log("扫码失败 =>", error);
                    }
            });
    }

2023/09/20

window.Notification 浏览器通知功能

    // 权限判断
    if (window.Notification) {
      // 浏览器通知--window.Notification
      if (Notification.permission == 'granted') {
        console.log('允许通知')
      } else if (Notification.permission != 'denied') {
        console.log('需要通知权限')
        Notification.requestPermission((permission) => {})
      }
    } else {
      console.error('浏览器不支持Notification')
    }
    
    // 发送通知的方法
    setTimeout(() => {
      new Notification('title', { body: 'notification body' })
    }, 5000)

2023/12/04

Vue3 NavieUI DataTable组件 动态max-height属性Hook

  • hook部分
import { useWindowSize, useDebounceFn } from '@vueuse/core';
const TabelThHeight = 50;
export const useTableFn = (thClass?: string, initHeight?: number) => {
  initHeight = initHeight ? initHeight : 100;
  thClass = thClass ? thClass : '.n-data-table-th';
  const { width, height } = useWindowSize(); // 窗口宽高
  const tableWrapper = ref<HTMLElement | undefined>();
  const maxHeight = ref<number>(initHeight); // 表格最大高度
  const reFreshFlag = ref(false); // 组件刷新用标志位
  const dataLodaing = ref(false); // 数据加载loading
  const getMaxHeight = () => {
    reFreshFlag.value = true;
    let height = tableWrapper.value?.clientHeight;
    // 动态获取表头高度
    let tableThHeightTemp = tableWrapper.value?.querySelector(thClass!)?.clientHeight;
    let tableThHeightNow = tableThHeightTemp ? tableThHeightTemp : TabelThHeight
    // 表体的最大高度为外框高度减去表头高度
    maxHeight.value = height ? (height - tableThHeightNow) : initHeight!;
    nextTick(() => {
      reFreshFlag.value = false;
    })
  }
  watch([
    () => width.value,
    () => height.value
  ], useDebounceFn(getMaxHeight));
  onMounted(() => {
    getMaxHeight();
  });
  return {
    maxHeight,
    reFreshFlag,
    dataLodaing,
    tableWrapper
  }
}
// 此处定义了一个Hooks 用于实时刷新表体最大高度
// 首先定义了一个初始的表头高度TabelThHeight
// 之后定义了Hooks函数 useTableFn 其接受2个参数 thClass initHeight 分别代表 表头的类名(可缺) 初始表体高度(可缺)
// 若后两者参数缺省 则会使用相关默认值
// 接着 定义了三个响应式变量 tableWrapper maxHeight reFreshFlag dataLodaing 分别代表 表格父盒子 表体最大高度 组件刷新用标志位 数据加载loading
// 同时 还使用了useWindowSize函数 获取windows宽高的响应式变量 height width
// 之后我们定义一个获取当前表体最大高度的函数 getMaxHeight
// 之后 我们使用watch监听器 监听height与width,在二者之一发生变化时,调用getMaxHeight函数, 同时这里使用了useDebounceFn函数进行函数防抖处理
// 最后导出响应式变量 tableWrapper maxHeight reFreshFlag dataLodaing

  // 相关页面导出此Hook后 将tableWrapper绑定在表格的父盒子的ref属性上 
  // 将 maxHeight reFreshFlag dataLodaing 分别绑定在表格的 max-height、v-if(v-if="!reFreshFlag")、loading上
  • 页面调用
<div class="w-full h-full" ref="tableWrapper">
    <!-- 组件其他属性请自行填写 -->
    <n-data-table :max-height="maxHeight" v-if="!reFreshFlag" :loading="dataLodaing" />
</div>
<script setup lang="ts">
import { useTableFn } from '@/hooks'
const { maxHeight, reFreshFlag, dataLodaing, tableWrapper } = useTableFn();
</script>