前端Excel热成像数据展示及插值算法

在这里插入图片描述

🎬 江城开朗的豌豆:个人主页

 🔥 个人专栏:《 VUE 》 《 javaScript 》

 📝 个人网站 :《 江城开朗的豌豆🫛 》 

⛺️生活的理想,就是为了理想的生活!

目录

📘 前言

📘一、热成像数据的导入与展示

📟 1.数据导入:

📟 2.创建热图:

📟3.数据可视化

📘二、插值算法的应用

📟 1.线性插值:

📟 2.双线性插值:

 📟 3.样条插值:

📘三、实例操作

📘 完整代码展示

📘 写在最后


📘 前言

热成像技术在工业、医学和科学研究中发挥了重要作用,它能够通过捕捉不同物体的温度分布图像来提供宝贵的信息。然而,要有效地展示和分析这些热成像数据,我们需要使用适当的工具和算法。本文将介绍如何使用Excel展示热成像数据,并实现插值算法以增强数据分析的准确性和可视化效果。

 原始图

 转换成功的效果图

📘一、热成像数据的导入与展示

热成像设备通常生成的是包含温度信息的二维数组数据。在Excel中展示这些数据,可以通过以下步骤

📟 1.数据导入

 将热成像数据以CSV或XLSX格式导入Excel。通常,这些数据以矩阵的形式存储,每个单元格代表一个温度值。

📟 2.创建热图

在Excel中,可以使用条件格式来创建热图。选择包含温度数据的单元格区域,应用“条件格式”中的“色阶”功能,以不同的颜色表示不同的温度范围。这种可视化方法能帮助快速识别热图中的热点区域。

📟3.数据可视化

  利用Excel的图表工具,将数据以图表形式展示。例如,可以创建散点图或折线图,帮助分析温度随时间或位置的变化

📘二、插值算法的应用

在热成像数据中,可能存在一些缺失值或数据点稀疏的情况。插值算法可以帮助我们估算这些缺失值,并提高数据的连续性。以下是一些常见的插值算法及其在Excel中的实现方法:

📟 1.线性插值

线性插值是最简单的插值方法,通过连接已知数据点的直线来估算未知点的值。在Excel中,可以通过线性回归或在两个已知数据点之间插入一个新的数据点来实现。

📟 2.双线性插值

双线性插值适用于二维数据,使用已知点形成的矩阵进行插值。你可以在Excel中创建一个新的数据表,通过公式计算每个数据点的插值值。双线性插值公式如下:

 📟 3.样条插值

样条插值是一种更复杂的插值方法,通过多项式拟合数据点,实现平滑的曲线插值。在Excel中,这种方法可以通过插件或VBA代码实现,虽然设置相对复杂,但可以生成更平滑的数据图。

📘三、实例操作

假设我们有一个包含热成像数据的Excel表格,我们可以通过以下步骤进行插值和数据展示:

  1. 创建数据表: 将热成像数据输入Excel,并使用条件格式创建热图。

  2. 应用插值算法: 使用Excel的插值公式填补缺失数据,或通过VBA实现更复杂的插值算法。

  3. 数据分析与优化: 根据插值后的数据,生成更精确的热图和图表。利用Excel的数据分析工具,评估数据的准确性和可靠性。

📘 完整代码展示

        

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Excel Heatmap with Canvas</title>
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>

    <style>
      #heatmapCanvas {
        /* border: 1px solid black; */
      }
    </style>
  </head>
  <body>
    <button onclick="chuNenFx()">储能分析</button>
    <input type="file" id="fileInput" />
    <input type="number" id="reLiNum" placeholder="输入数字" />
    <button onclick="getValue()">获取值</button>  
    <button onclick="showMaxTemperature()">显示最高温度</button>
    <button onclick="showMinTemperature()">显示最低温度</button>
    <br />
    <button onclick="highlightMaxTemperature()">标记最高温度</button>
    <button onclick="highlightMinTemperature()">标记最低温度</button>

    <canvas id="heatmapCanvas"></canvas>
    <script>
      document
        .getElementById("fileInput")
        .addEventListener("change", handleFileSelect, false);
      // 双线性插值算法
      var newData = [];
      function processFile() {
        const fileInput = document.getElementById("fileInput");
        const file = fileInput.files[0];
        const reader = new FileReader();
        reader.onload = function (event) {
          const data = new Uint8Array(event.target.result);
          const workbook = XLSX.read(data, { type: "array" });
          const sheetName = workbook.SheetNames[0];
          const worksheet = workbook.Sheets[sheetName];
          const csv = XLSX.utils.sheet_to_csv(worksheet);
          const arrayData = csvToArray(csv);
          const interpolatedData = interpolate22(arrayData, 480, 640); // 增加到 240, 320 的分辨率   1440, 1920 --  384, 512
          //   console.log("Interpolated", interpolatedData);
          const szNew = interpolatedData
            .map((row) => row.map((cell) => Math.round(cell)))
            .map(
              (row) => row.filter((cell) => cell !== 0) // 过滤掉值为 0 的元素
            );
          console.log(szNew);
          newData = szNew;
        };
        reader.readAsArrayBuffer(file);
      }

      function interpolate22(data, newRows, newCols) {
        const rows = data.length;
        const cols = data[0].length;
        const interpolatedData = Array.from({ length: newRows }, () =>
          Array(newCols).fill(0)
        );

        for (let i = 0; i < newRows; i++) {
          for (let j = 0; j < newCols; j++) {
            const xRatio = (j / (newCols - 1)) * (cols - 1);
            const yRatio = (i / (newRows - 1)) * (rows - 1);
            const x0 = Math.floor(xRatio);
            const x1 = Math.min(x0 + 1, cols - 1);
            const y0 = Math.floor(yRatio);
            const y1 = Math.min(y0 + 1, rows - 1);

            const q11 = data[y0][x0];
            const q21 = data[y0][x1];
            const q12 = data[y1][x0];
            const q22 = data[y1][x1];

            const r1 = (x1 - xRatio) * q11 + (xRatio - x0) * q21;
            const r2 = (x1 - xRatio) * q12 + (xRatio - x0) * q22;

            interpolatedData[i][j] = (y1 - yRatio) * r1 + (yRatio - y0) * r2;
          }
        }

        return interpolatedData;
      }

      // 最大值

      function getMaxTemperature(data) {
        let maxTemp = -Infinity;
        for (const row of data) {
          for (const temp of row) {
            if (temp > maxTemp) {
              maxTemp = temp;
            }
          }
        }
        return maxTemp;
      }
      //   插值算法封装
      function interpolate(data, newRows, newCols) {
        const rows = data.length;
        const cols = data[0].length;
        const x = Array.from({ length: cols }, (_, i) => i);
        const y = Array.from({ length: rows }, (_, i) => i);

        const interpolatedData = Array.from({ length: newRows }, (_, i) => {
          return Array.from({ length: newCols }, (_, j) => {
            const xRatio = (j / (newCols - 1)) * (cols - 1);
            const yRatio = (i / (newRows - 1)) * (rows - 1);
            const x0 = Math.floor(xRatio);
            const x1 = Math.min(x0 + 1, cols - 1);
            const y0 = Math.floor(yRatio);
            const y1 = Math.min(y0 + 1, rows - 1);

            const q11 = data[y0][x0];
            const q21 = data[y0][x1];
            const q12 = data[y1][x0];
            const q22 = data[y1][x1];

            const r1 = (x1 - xRatio) * q11 + (xRatio - x0) * q21;
            const r2 = (x1 - xRatio) * q12 + (xRatio - x0) * q22;

            return (y1 - yRatio) * r1 + (yRatio - y0) * r2;
          });
        });

        return interpolatedData;
      }
      function csvToArray(text) {
        return text.split("\n").map((row) => row.split(",").map(Number));
      }

      var maxTemperature = [];

      // 最小值
      function getMinTemperature(data) {
        let minTemp = Infinity;
        for (const row of data) {
          for (const temp of row) {
            if (temp < minTemp) {
              minTemp = temp;
            }
          }
        }
        return minTemp;
      }
      // 显示最低温度
      function showMinTemperature() {
        const minTemperature = getMinTemperature(maxTemperature);
        alert(`最低温度是: ${minTemperature / 100}°C`);
      }

      function showMaxTemperature() {
        if (maxTemperature.length > 0) {
          const maxTempe = getMaxTemperature(maxTemperature);
          alert(`最高温度是: ${maxTempe / 100}°C`);
        } else {
          alert(`最高温度是: 请先上传数据`);
        }
      }
      // 封装双线性插值算法
      function bilinearInterpolate(x, y, values) {
        const x1 = Math.floor(x);
        const y1 = Math.floor(y);
        const x2 = Math.ceil(x);
        const y2 = Math.ceil(y);

        const Q11 = values[y1] ? values[y1][x1] : 0;
        const Q12 = values[y1] ? values[y1][x2] : 0;
        const Q21 = values[y2] ? values[y2][x1] : 0;
        const Q22 = values[y2] ? values[y2][x2] : 0;

        const xFraction = x - x1;
        const yFraction = y - y1;

        const R1 = Q11 * (1 - xFraction) + Q12 * xFraction;
        const R2 = Q21 * (1 - xFraction) + Q22 * xFraction;

        return R1 * (1 - yFraction) + R2 * yFraction;
      }
      // 获取excel数据
      async function handleFileSelect(event, json) {
        await processFile();
        const file = event.target.files[0];
        // console.log("=====>>>", file);

        if (!file) return;

        const reader = new FileReader();
        reader.onload = function (e) {
          const data = new Uint8Array(e.target.result);
          const workbook = XLSX.read(data, { type: "array" });

          // Assuming you want to process the first sheet
          const sheetName = workbook.SheetNames[0];
          const worksheet = workbook.Sheets[sheetName];
          //   const json = XLSX.utils.sheet_to_json(worksheet, {
          //     header: 1,
          //     defval: 0,
          //   });
          // Default values for empty cells

          // Convert data to 2D array
          //   console.log("===========json=====================", json);
          const dataArray = newData.map((row) =>
            row.map((cell) => parseFloat(cell) || 0)
          );
          //   console.log("Data Array:", dataArray);
          maxTemperature = dataArray;
          //   console.log("=workbook===" + maxTemperature);

          drawHeatmap(dataArray);
        };
        reader.readAsArrayBuffer(file);
      }

      // 插值算法
      const canvas = document.getElementById("heatmapCanvas");
      //   const cellSize = 10; // 原始单元格大小
      let newCellSize = 1; // 插值后的单元格大小
      function getValue() {
        const inputElement = document.getElementById("reLiNum");
        const value = inputElement.value; // 获取输入的值
        newCellSize = value;
        drawHeatmap(maxTemperature); // 重新绘制热力图
      }
      //   页面跳转
      function chuNenFx() {
        window.location.replace("./boxEchars.html");
      }

      //   绘制热力图
      function drawHeatmap(dataArray) {
        const width = dataArray[0].length;
        const height = dataArray.length;

        // 计算新画布的宽度和高度
        const canvasWidth = width * newCellSize;
        const canvasHeight = height * newCellSize;
        // Adjust canvas size
        canvas.width = canvasWidth; // Scale width
        canvas.height = canvasHeight; // Scale height

        const ctx = canvas.getContext("2d");
        const imageData = ctx.createImageData(canvasWidth, canvasHeight);

        // 查找归一化的最小值和最大值
        let min = Infinity;
        let max = -Infinity;
        dataArray.flat().forEach((value) => {
          if (value < min) min = value;
          if (value > max) max = value;
        });

        // 生成热力图
        for (let y = 0; y < canvasHeight; y++) {
          for (let x = 0; x < canvasWidth; x++) {
            const dataX = x / newCellSize;
            const dataY = y / newCellSize;

            const value = bilinearInterpolate(dataX, dataY, dataArray);

            // const value = dataArray[y][x];
            const normalizedValue = (value - min) / (max - min);
            // for (let dy = 0; dy < cellSize; dy++) {
            //     for (let dx = 0; dx < cellSize; dx++) {
            //         const index = ((y * cellSize + dy) * canvas.width + (x * cellSize + dx)) * 4;
            //         const color = getHeatmapColor(normalizedValue);

            //         imageData.data[index] = color[0];
            //         imageData.data[index + 1] = color[1];
            //         imageData.data[index + 2] = color[2];
            //         imageData.data[index + 3] = 255;
            //     }
            // }

            // // 获取颜色值
            const color = getHeatmapColor(normalizedValue);
            // 设置画布上的像素颜色
            const index = (y * canvasWidth + x) * 4;
            imageData.data[index] = color[0]; // Red
            imageData.data[index + 1] = color[1]; // Green
            imageData.data[index + 2] = color[2]; // Blue
            imageData.data[index + 3] = 255; // Alpha
          }
        }
        // console.log("imageDat", imageData);
        ctx.putImageData(imageData, 0, 0);
      }

      // 找到最高温度及其位置
      function getMaxTemperatureInfo(isMax) {
        let extremeTemp = isMax ? -Infinity : Infinity;
        let position = { row: 0, col: 0 };

        maxTemperature.forEach((row, rowIndex) => {
          row.forEach((temp, colIndex) => {
            if (
              (isMax && temp > extremeTemp) ||
              (!isMax && temp < extremeTemp)
            ) {
              extremeTemp = temp;
              position = { row: rowIndex, col: colIndex };
            }
          });
        });

        return { extremeTemp, position };
      }

      // 找到最高温度及其位置
      //   function getMaxTemperatureInfo() {
      //     let maxTemp = -Infinity;
      //     let position = { row: 0, col: 0 };
      //     maxTemperature.forEach((row, rowIndex) => {
      //       row.forEach((temp, colIndex) => {
      //         if (temp > maxTemp) {
      //           maxTemp = temp;
      //           position = { row: rowIndex, col: colIndex };
      //         }
      //       });
      //     });
      //     return { maxTemp, position };
      //   }

      // 标记最高温度
      function highlightMaxTemperature() {
        const { extremeTemp, position } = getMaxTemperatureInfo(true);
        drawHeatmap(maxTemperature); // 重新绘制热力图
        const ctx = canvas.getContext("2d");

        // 绘制标记
        ctx.strokeStyle = "yellow";
        ctx.lineWidth = 30;
        ctx.beginPath();
        const x = position.col * newCellSize + newCellSize / 2;
        const y = position.row * newCellSize + newCellSize / 2;
        ctx.arc(x, y, newCellSize / 4, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.fillStyle = "yellow";
        ctx.fill();
        // alert(`最高温度是: ${extremeTemp/100}°C`);
        // 显示温度值
        ctx.fillStyle = "black";
        ctx.font = "12px Arial";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(`${extremeTemp / 100}°C`, x, y);
      }
      // 标记最低温度
      function highlightMinTemperature() {
        const { extremeTemp, position } = getMaxTemperatureInfo(false);
        drawHeatmap(maxTemperature); // 重新绘制热力图
        const ctx = canvas.getContext("2d");

        // 绘制标记
        ctx.strokeStyle = "green";
        ctx.lineWidth = 30;
        ctx.beginPath();
        const x = position.col * newCellSize + newCellSize / 2;
        const y = position.row * newCellSize + newCellSize / 2;
        ctx.arc(x, y, newCellSize / 4, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.fillStyle = "green";
        ctx.fill();
        // alert(`最低温度是: ${extremeTemp/100}°C`);
        // 显示温度值
        ctx.fillStyle = "white";
        ctx.font = "12px Arial";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(`${extremeTemp / 100}°C`, x, y);
      }

      function getHeatmapColor(value) {
        // 从蓝色到红色的简单热图颜色渐变
        const r = Math.min(255, Math.max(0, Math.floor(255 * value)));
        const g = Math.min(255, Math.max(0, Math.floor(255 * (1 - value))));
        const b = 0;
        return [r, g, b];
      }
    </script>
  </body>
</html>


📘 写在最后

Excel作为一种强大的数据处理工具,可以有效地展示和分析热成像数据。通过合理使用插值算法,可以提升数据的连续性和可视化效果。希望本文能帮助你更好地利用Excel进行热成像数据的展示和分析。如果你有更复杂的数据需求,也可以考虑结合使用专业的数据分析工具和编程语言。

通过掌握这些基本技巧,你将能够更好地理解和利用热成像数据,为你的工作和研究提供有力支持。

感谢大家一如既往对我的点赞与支持,不是我的作品有多好,而是你们的不嫌弃。这世界上有一种爱叫“关注”,感恩遇见、感恩有你~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/875978.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器数据增量迁移方案-—SAAS本地化及未来之窗行业应用跨平台架构

一、数据迁移增量同步具有以下几个优点&#xff1a; 1. 减少数据传输量&#xff1a;只传输自上次同步以来更改的数据&#xff0c;而不是整个数据集&#xff0c;这显著降低了网络带宽的使用和传输时间。 2. 提高同步效率&#xff1a;由于处理的数据量较小&#xff0c;同步过程…

MyBatis中Collection和Association的底层实现原理

MyBatis中Collection和Association的底层实现原理 Hi &#x1f44b;, Im shy 有人见尘埃&#xff0c;有人见星辰 技术咨询 引言 在 MyBatis 中&#xff0c;<collection> 和 <association> 标签用于处理一对多和一对一的关系。这两个标签在底层通过缓存、对象创…

以系统工程为指导的军品设计、开发与管理常用方法培训

课程背景&#xff1a; 产品开发和产品管理是组织经营战略的核心&#xff0c;而经营战略又为组织的创新战略、产品开发和产品管理提供了环境和方向。使命、愿景与核心价值观对于产品开发的聚焦点和管理方式都具有十分重要的作用。产品开发通常被称为组织的“血液”&#xff0c;…

node.js框架StrongLoop快速入门实战

目录 一、StrongLoop框架简介 二、安装StrongLoop框架 三、创建项目my-loopback-project 四、项目布局和结构 五、配置连接mysql数据库 六、实现自动生成api接口 一、StrongLoop框架简介 StrongLoop是一个强大的框架&#xff0c;它基于Node.js构建&#xff0c;几乎涵盖了…

《信息系统安全》课程实验指导

第1关&#xff1a;实验一&#xff1a;古典密码算法---代换技术 任务描述 本关任务&#xff1a;了解古典密码体制技术中的代换技术&#xff0c;并编程实现代换密码的加解密功能。 注意所有明文字符为26个小写字母&#xff0c;也就是说字母表为26个小写字母。 相关知识 为了完…

【开源免费】基于SpringBoot+Vue.JS高校心理教育辅导系统(JAVA毕业设计)

本文项目编号 T 031 &#xff0c;文末自助获取源码 \color{red}{T031&#xff0c;文末自助获取源码} T031&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计 六、核…

JEE 设计模式

Java 数据访问对象模式 Java设计模式 - 数据访问对象模式 数据访问对象模式或DAO模式将数据访问API与高级业务服务分离。 DAO模式通常具有以下接口和类。 数据访问对象接口定义模型对象的标准操作。 数据访问对象类实现以上接口。可能有多个实现&#xff0c;例如&#xff0c…

LVGL学习

注&#xff1a;本文使用的lvgl-release-v8.3版本&#xff0c;其它版本可能稍有不同。 01 LVGL模拟器配置 day01-02_课程介绍_哔哩哔哩_bilibili LVGL开发教程 (yuque.com) 如果按照上述视频和文档中配置不成功的话&#xff0c;直接重装VsCode&#xff0c;我的就是重装以后就…

Git提交有乱码

服务器提交记录如图 可知application.properties中文注释拉黄线 &#xff0c;提示Unsupported characters for the charset ISO-8859-1 打开settings - Editor - File Encodings 因为我们项目的其他文件都是UTF-8&#xff0c;所以&#xff0c;我们将默认值都改成UTF-8 然后…

打造民国风格炫酷个人网页:用HTML和CSS3传递民国风韵

附源码&#xff01;&#xff01;&#xff01; 感谢支持 小弟不断创作网站demo感兴趣的可以关注支持一下 对了 俺在结尾带上了自己用的 背景 大家可以尝试换一下效果更好哦~~~ 如何创建一个民国风格的炫酷网页 在这篇博客中&#xff0c;我们将展示如何制作一个结合民国风格和…

【无标题】Efinity 0基础进行流水灯项目撰写(FPGA)

文章目录 前言一、定义概念 缩写1. 二、性质1.2. 三、使用步骤编译常见错误1. 没加分号2. end 写多了 编译成功的标志总结参考文献 前言 数电课设 使用 FPGAIDE 使用 Efinity 一、定义概念 缩写 1. 二、性质 1. 2. 三、使用步骤 python代码块matlab代码块c代码块编译…

Vue3+CesiumJS相机定位camera

new Cesium.Camera (scene) 摄像机由位置&#xff0c;方向和视锥台定义。 方向与视图形成正交基准&#xff0c;上和右视图x上单位矢量。 视锥由6个平面定义。每个平面都由 Cartesian4 对象表示&#xff0c;其中x&#xff0c;y和z分量定义垂直于平面的单位矢量&#xff0c;w分量…

C++《类和对象》(下)

在之前类和对象&#xff08;中&#xff09;我们学习了类当中的6大默认成员函数&#xff0c;我们了解了6大成员函数的结构特征和特点以及在不同情况各个成员函数是如何调用的&#xff0c;那么接下来我们在本篇当中将继续学习之前在学习构造函数中未了解的初始化列表&#xff0c;…

【Python】生成图片验证码

1. 首先安装第三方库PIL&#xff08;图像处理库&#xff09; pip install pillow 2. 编写生成验证码代码 这里字体 SimHei.ttf 文件要放在该文件目录下。 import random from PIL import Image, ImageDraw, ImageFont, ImageFilterdef check_code(width128, height30, char…

ros学习笔记.4 Path Planning Part 2 (避障)

避障是如何工作的什么是局部规划器&#xff1f;什么是局部成本图&#xff1f;路径规划回顾如何使用动态重新配置和其他 Rviz 工具 局部规划器 一旦全局规划器计算出要遵循的路径&#xff0c;该路径就会发送给局部规划器。然后&#xff0c;局部规划器将执行全局规划的每个部分&…

比较stl库的ostringstream与Qt的QString::arg(),QString::number()

需求&#xff1a; 显示一个float或者double类型的数&#xff0c;要求小数点后的数字位数为定值。 考虑STL库的ostringstream或者Qt的QString::arg(), number 对于stringstream,使用比较繁琐&#xff0c;要联合使用std::fixed和std::setprecision才能实现固定小数位数显示&am…

UE5-俯视角色移动(蓝图)01

效果如下&#xff1a; 蓝图节点如下&#xff1a; 使用示例自带的移动蓝图&#xff0c;发现角色只能平移&#xff0c;不会转向。必须勾选以下选项&#xff1a; 点击蓝图-》组件-》SpringArm节点。在细节中找到摄像机设置&#xff0c;勾选以下&#xff1a; 在 点击蓝图-》组件-…

PowerShell install 一键部署Oracle21c-xe

Oracle21c-xe前言 无论您是开发人员、DBA、数据科学家、教育工作者,还是仅仅对数据库感兴趣,Oracle Database Express Edition (XE) 都是理想的入门方式。它是全球企业可依赖的强大的 Oracle Database,提供简单的下载、易于使用和功能齐全的体验。您可以在任何环境中使用该…

Qt多语言/多语种详细开发教程

Qt作为跨平台的开发工具&#xff0c;早已应用到各行各业的软件开发中。 今天讲讲&#xff0c;Qt开发的正序怎么做多语言开发。就是说&#xff0c;你设置中文&#xff0c;就中文显示&#xff1b;设置英语就英文显示&#xff0c;设置繁体就繁体显示&#xff0c;设置发育就显示法语…

Vue3+TS项目给el-button统一封装一个点击后转圈效果的钩子函数按钮防抖

前言 每个按钮都要单独定义一个loading变量&#xff0c;并且在接口请求前修改为true&#xff0c;接口响应后再修改为false&#xff0c;封装后这段重复的逻辑就可以统一管理不用每次都写一遍了。 效果 新建一个公共的src\common.ts import { ref } from "vue"expor…