菜鸟做项目时发现很多 vue3 常用的代码,所以来总结一下!

监听路由

import { useRoute } from "vue-router";
let router = useRoute();
watch(
  () => router.path,
  (newValue, oldValue) => {
    console.log("watch", newValue, oldValue);
  },
  { immediate: true }
);

这里顺便补充一下 路由跳转跨界面跳转获取参数

路由跳转

import { useRouter, useRoute } from "vue-router";
const router = useRouter();
const route = useRoute();

// 跳转路由
const toPath = function (path) {
  if (route.path !== path.path) {
    //判断当前路径与跳转路径是否相同
    router.push(path);
  }
};

跨界面跳转

import { useRouter } from "vue-router"; 
// 新标签页跳转
const router = useRouter();
const openPage = (params = "") => {
  let href = null;
  if (params) {
    href = router.resolve({
      path: "/newform",
      query: {
        id: JSON.stringify(params),
      },
    });
  } else {
    href = router.resolve({
      path: "/newform",
      query: {
        id: null,
      },
    });
  }
  window.open(`${href.href}`, "_blank");
};

这里也可以使用 name:“newform” ,要和自己router里面定义的保持 对应关系

动态路由也是一样:
在这里插入图片描述
普通路由两个同时写也没有问题,但是动态路由不行,会报错!!!
在这里插入图片描述
报错:runtime-core.esm-bundler.js:343 Uncaught Error: Missing required param “xxx”
在这里插入图片描述

获取参数

import { useRoute } from "vue-router";
const route = useRoute();
console.log(route.query.id); // 这里有两种一种 params、一种 query,注意取的时候要对应!

且要分清 动态路由(params)路由后面带参数(query) 这两种情况!具体看文章:23 动态路由(路由传参)

mitt、project / inject 无效

如果通信的组件是 router-view 里面 根据路由加载的 或者 路由有两层嵌套,那么不管是 mitt 还是 project/inject 都无法进行组件间的通信,因为 mitt 要能通信必须是该界面已经加载出来了!而 project/inject 不知道为什么,嵌套了两层后,第二层 router-view 里面的组件就无法获取了,会报错

[Vue warn]: injection "openmenu" not found. 
  at <Resources onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > > 
  at <RouterView> 
  at <ElMain> 
  at <ElContainer> 
  at <Home onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > > 
  at <RouterView> 
  at <App>

好像是因为第一层 router-view 被卸载了,所以 project 为 undefined 了!也可能是因为 provide 只能够向下进行传递数据,而路由并不相当于是其子组件!

解决方案

使用pinia、vuex等!

防抖函数 (已封装)

/**
 * 防抖函数
 * @param {function} fn
 * @param {number} delay
 * @returns {function}
 * 如果函数有参数,直接定义一个常量等于debounce(fn,delay)
 * 调用的时候直接 常量(函数参数) 就行
 *
 */
export const debounce = (fn, delay) => {
  let timer = null;
  return function () {
    let context = this;
    let args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(context, args);
    }, delay);
  };
};

复制函数封装

复制函数

/**
 * 复制文本到粘贴板
 * @param {*} txt 需要粘贴的文本
 * @returns {function}
 *
 */
export let copyTxt = (txt) => {
  // 惰性函数
  if (navigator.clipboard) {
    copyTxt = (txt) => {
      navigator.clipboard.writeText(txt);
    };
    copyTxt(txt);
  } else {
    copyTxt = (txt) => {
      const input = document.createElement("input");
      input.setAttribute("value", txt);
      document.body.appendChild(input);
      input.select();
      document.execCommand("copy");
      document.body.removeChild(input);
    };
    copyTxt(txt);
  }
};

下载函数(get)

下载函数(get)

下载和请求接口的逻辑不太一样,只需要访问就行了,菜鸟有时候也容易忘记,所以这里记一下!

/**
 * 判断是否是微信浏览器
 */
export const isWxBrowser = () => {
  // 判断是否H5微信环境,true为微信浏览器
  const ua = navigator.userAgent.toLowerCase();
  return ua.match(/MicroMessenger/i) == "micromessenger" ? true : false;
};
/**
 * 下载工具
 * @param {string} url 下载地址
 * @param {string} name 文件名
 *
 */
export const downloadTool = (url, name = "") => {
  // 微信内置浏览器要提示
  if (isWxBrowser()) {
    // eslint-disable-next-line
    ElMessage({
      message: "请先在浏览器中打开再下载!",
      type: "error",
    });
  } else {
    let a = document.createElement("a");
    a.style = "display: none"; // 创建一个隐藏的a标签
    a.href = url;
    a.download = name;
    document.body.appendChild(a);
    a.click(); // 触发a标签的click事件
    document.body.removeChild(a);
  }
};

post

当然有时候下载传入的参数比较多,那么后端是可能将下载变成post请求的,这个时候要进行如下修改:

function downloadFileFun(formType) {
    const params = {
      formType,
    };
    downloadFile(params)
      .then((res) => {
        // console.log(res);
        // 从响应中获取文件数据
        const fileData = res;
        // 创建一个Blob对象
        let blob = new Blob([fileData], { type: "application/vnd.ms-excel" });
        // 生成文件URL
        const downloadUrl = URL.createObjectURL(blob);
        downloadTool(downloadUrl, "模板表.xlsx");
      })
      .catch((err) => {
        console.log(err);
      });
  }
}

注意

downloadFile 这个api里面要加一个responseType: “blob”:

export function downloadFile(params) {
  return request({
    url: "/user/downloadExcel",
    method: "POST",
    data: params,
    responseType: "blob",
  });
}

如果是 pdf ,这里要修改为 :

let blob = new Blob([fileData], { type: "application/pdf" });

responseType: "arraybuffer",

如果后端不仅会返回数据,有时候还会返回报错信息的话,就需要对返回的结果进行判断,因为只要使用了 responseType 就算返回的不是数据类型,也会强制转换,那么报错信息就变成了 blob数据对象 了,没有data、message等东西了,需要将数据对象转换回json对象,代码如下:

createReportApi(formdata.value)
   .then((res) => {
     console.log(res);
     loading.close();
     // 非文件数据,长度会较小
     if (res.byteLength <= 100) {
       const jsonString = new TextDecoder("utf-8").decode(res);
       const jsonObject = JSON.parse(jsonString);
       console.log(jsonObject);
       // eslint-disable-next-line
       ElMessage({
         message: jsonObject.message,
         type: "error",
       });
     } else {
       let blob = new Blob([res], { type: "application/pdf" });
       downloadTool(
         window.URL.createObjectURL(blob),
         `${formdata.value.contractNum}-${formdata.value.projectName}.pdf`
       );
     }
   })
   .catch((err) => {
     console.log(err);
     loading.close();
   });

更多常见代码见:常用代码:vue必须配置的部分代码、element ui按需引入、vue动态绑定背景、自适应js、禁止放大、播放声音、store的使用、websocket封装、echarts、swiper

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐