js(vue)如何实现页面截图,向后端传递,生成PDF

news/2024/9/17 8:08:20/ 标签: vue.js, javascript, 前端

利用 htmm12canvas

首先引入

javascript">npm install express multer
# 或者
yarn add express multer

代码如下:

javascript"><template><!-- <div style="width:100%;height:100%;overflow-y: scroll"><img :src="svg" style="width: 100%;" /></div> --><div class="backScreen">中间代码省略</div>
</template><script setup>import { nextTick, ref, provide } from "vue";
import { useGetResizeBodySize } from '@/hooks/useGetScaleHeight'import EquConsumeSpareRank from './charts/EquConsumeSpareRank'
import EquPurchaseSpareRank from './charts/EquPurchaseSpareRank'
import SpareConsumeRank from './charts/SpareConsumeRank'
import SpareOverView from './charts/SpareOverView'
import StoreAvgDurationRank from './charts/StoreAvgDurationRank'
import StoreInactive from './charts/StoreInactive'import img169 from './imgs/dp_16.9.svg'
import img1610 from './imgs/dp_16.10.svg'
import html2canvas from 'html2canvas';const imageWidth = ref('100%')
const imageHeight = ref('100%')
const backImg = ref(img169)
const fullScreen = ref(false)
const margin = ref(0)provide('screenHeight', imageHeight)useGetResizeBodySize(e => {const { screenWidth, screenHeight } = eimageWidth.value = screenWidthimageHeight.value = screenHeightconsole.log('imageHeight.value', imageHeight.value)// 上下的marginmargin.value = imageHeight.value * 0.02// console.log('outer', window.outerWidth, window.outerHeight, screenWidth, screenHeight)const ratio = screenWidth/screenHeightif (ratio === 16/9 || ratio === 16/10) {fullScreen.value = true}if (ratio === 16/10) {backImg.value = img1610}else {backImg.value = img169}})// 定义截图和发送截图的方法   下面是关键代码
const captureScreen = async () => {return new Promise((resolve, reject) => {nextTick(() => {html2canvas(document.querySelector('.backScreen'), {logging: false,scale: 2,useCORS: true,}).then(canvas => {canvas.toBlob(blob => resolve(blob), 'image/png');}).catch(err => reject(err));});});
};const sendToServer = async (blob) => {try {const formData = new FormData();formData.append('image', blob, 'screenshot.png');console.log("发送图片给后台")const response = await fetch('http://127.0.0.1:8081/test/upload-image', {method: 'POST',body: formData,});if (!response.ok) {throw new Error(`HTTP error! Status: ${response.status}`);}const data = await response.json();console.log(data);} catch (error) {console.error('Failed to send screenshot:', error);}
};// 监听键盘事件
const handleKeyPress = (event) => {// 检查是否按下了 "O" 键if (event.key === 'o' || event.keyCode === 79) {console.log("O键被按下")event.preventDefault(); // 防止默认行为captureScreen().then(blob => {sendToServer(blob);}).catch(error => {console.error('Error capturing screen:', error);});}
};// 在组件挂载后添加键盘事件监听器
onMounted(() => {document.addEventListener('keydown', handleKeyPress);// 清除引用以防止内存泄漏onUnmounted(() => {document.removeEventListener('keydown', handleKeyPress);});
});</script><style lang="scss" scoped>
:deep .el-input__wrapper {height: 22px;font-size: 10px;background-color: #ABD6FF;// background-color: transparent;/* border: 0px !important; */box-shadow: none;
}
.chartRow {width: 100%;height: 400;display: flex;justify-content: space-between;
}
.backScreen {width: 100%;height: 100%;display: flex;justify-content: center;// align-items: center;position: relative;// overflow: auto;// background-color: lightgray;// background-image: url('./img/bk.svg');// background-size: cover;// background-clip: border-box;// background-repeat: no-repeat;.backImg {position: absolute;left: 0;top: 0;right: 0;bottom: 0;}.contentBack {// background-color: white;// margin: 11% 120px;margin-top: 6%;margin-left: 6%;margin-right: 6%;flex: 1;z-index: 10;height: 82%;.card {width: 430px;height: 100%;// height: 370px;background-size: 100% 100%;background-color: #0241A2;border-radius: 20px;overflow: hidden;display: flex;flex-direction: column;.card_title {width: 100%;height: 46px;background: linear-gradient(#1187FB, #0241A2);border-radius: 20px 20px 0 0;padding: 13px 0 0 24px;color: #30D9FF}}.cardMax {// height: 370px;height: 100%;background-size: 100% 100%;background-color: #0241A2;border-radius: 20px;display: flex;flex-direction: column;flex: 1;overflow: hidden;.cardMax_title {width: 100%;height: 46px;background: linear-gradient(#1187FB, #0241A2);border-radius: 20px 20px 0 0;padding: 13px 0 0 24px;color: #30D9FF}}}}
</style>

然后是后台很简单的实现,至于生成PDF再说


@RestController
@RequestMapping("test")
@Api(value = "ImageUploadController", tags = "截图导入接口")
public class ImageUploadController {@PostMapping("/upload-image")public ServiceResponse<String> handleFileUpload(@RequestParam("image") MultipartFile file) {if (file.isEmpty()) {throw new RuntimeException("文件为空");}ServiceResponse<String> response = new ServiceResponse<>();// 将图片保存到 D:\tu\ 目录下String filePath = "D:\\tu\\" + file.getOriginalFilename();try {file.transferTo(new File(filePath));response.setSucess("上传成功");} catch (Exception e) {response.setError("上传失败");}return response;}
}

如果是针对指定范围的

就在其div加上唯一id

javascript"><div id="inactive-store-div" class="chartRow" :style="{'marginTop': margin + 'px', height: (0.4 * imageHeight) + 'px'}"><div class="card"><div class="card_title"><span>设备采购备件排名</span></div><EquPurchaseSpareRank :width="'430'" :height="'260'" @equCountsMfrs="equCountsMfrs"></EquPurchaseSpareRank></div><div class="cardMax" :style="{'margin-left': margin + 'px', 'margin-right': margin + 'px'}"><div class="cardMax_title"><span>备件消耗量排名</span></div><SpareConsumeRank :width="'800'" :height="'260'" @equCountsMfrs="equCountsMfrs"></SpareConsumeRank></div><div class="card"><div class="card_title"><span>呆滞库存统计</span></div><StoreInactive :width="'455'" :height="'260'" @equCountsMfrs="equCountsMfrs"></StoreInactive></div></div>

然后这里js改成

javascript">const captureScreen = async () => {return new Promise((resolve, reject) => {nextTick(() => {// html2canvas(document.querySelector('.backScreen'), {   //针对全屏html2canvas(document.querySelector('#inactive-store-div'), {   //针对指定的范围logging: false,scale: 2,useCORS: true,}).then(canvas => {canvas.toBlob(blob => resolve(blob), 'image/png');}).catch(err => reject(err));});});
};


http://www.ppmy.cn/news/1522765.html

相关文章

【H2O2|全栈】关于HTML(3)HTML基础(二)

HTML相关知识 目录 HTML相关知识 前言 准备工作 标签的具体分类&#xff08;二&#xff09; 本文中的标签在什么位置使用&#xff1f; 本期前置知识点 超文本 超文本引用和源属性 图片标签 锚链接 iframe 锚点 预告和回顾 后话 前言 本系列博客将分享HTML相关…

SprinBoot+Vue应急信息管理系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

docker ps -a及docker exec -it ubuntu-01 /bin/bash

docker ps -a 命令 在 Docker 中用于列出 Docker 宿主机上所有的容器&#xff0c;包括正在运行的容器和已经停止的容器。这个命令是 Docker 用户常用的命令之一&#xff0c;用于查看和管理容器。 命令解析&#xff1a; docker&#xff1a;这是 Docker 的命令行接口&#xff…

Pytest-@pytest.fixture夹具篇(一)

一、定义 在Python的pytest测试框架中&#xff0c;pytest.fixture是一个&#xff08;不是唯一&#xff09;装饰器&#xff0c;用于定义一个测试夹具。 二、简单实例 使用参数autouserTrue pytest.fixture(autouseTrue) def my_fixture():print("Setup: 准备测试环境&q…

html导航栏logo

设置顶部logo <link rel"shortcut icon" href"图片路径" type"image/x-icon"> 显示效果&#xff1a; 这样设置可以是本地的&#xff0c;也可以是在线的。

【数学建模学习手册】python基本入门使用

本专栏内容为&#xff1a;数学建模原理 记录学习数学建模 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;数学建模 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学…

极米科技:走出舒适圈,推动数据架构现代化升级 | OceanBase 《DB大咖说》

《DB 大咖说》第 13 期&#xff0c;邀请到了极米科技软件与创新产品线高级架构师施刘凡来进行分享。 在小红书平台上&#xff0c;“是否应将家里的电视升级为投影仪&#xff1f;”这一话题激发了上百万篇笔记的分享与推荐&#xff0c;反映出年轻群体对投影仪的偏好。随着手机、…

【Linux】理解Linux中的软链接与硬链接

文章目录 理解Linux中的软链接与硬链接1. 什么是硬链接&#xff1f;示例&#xff1a; 2. 什么是软链接&#xff1f;示例&#xff1a; 3. 软链接与硬链接的对比4. 何时使用软链接与硬链接&#xff1f; 理解Linux中的软链接与硬链接 在Linux文件系统中&#xff0c;软链接&#x…

Android UI绘制流程

UI绘制流程&#xff0c;Activity、Dialog、PopupWindow等 -- android系统的事件分发流程分为很多部分&#xff1a; Native层 –> ViewRootImpl层 –> DecorView层 –> Activity层 –> ViewGroup层 –> View层。 其实Toast窗口和Activity、Dialog、PopupWindow有…

Java 中 `==` 和 `equals()` 的区别详解

在 Java 编程中&#xff0c; 和 equals() 是两种常用于比较变量和对象的方法。尽管它们都可以用来比较&#xff0c;但它们的作用和使用场景是不同的。本文将深入探讨它们之间的区别&#xff0c;并通过示例解释如何正确使用它们。 1. 操作符 什么是 &#xff1f; 是 Java 中的…

24并发设计模式——线程池模式

一、线程池模式介绍 线程池模式&#xff08;Thread Pool Pattern&#xff09;是一种并发设计模式&#xff0c;用于管理和循环使用线程资源以处理大量任务。它旨在提高系统性能和资源利用率&#xff0c;特别是在需要频繁创建和销毁线程的环境中。 1、线程池模式结构图 线程池管…

wmv怎么转换成视频mp4?简单的几种视频格式转换方法

wmv怎么转换成视频mp4&#xff1f;在数字媒体日益普及的今天&#xff0c;我们经常会遇到需要转换视频格式的情况。wmv格式&#xff0c;由微软开发&#xff0c;广泛用于Windows平台上播放视频。尽管wmv格式在Windows系统中表现优异&#xff0c;但其兼容性在其他操作系统或设备上…

为什么我选择这款PR剪辑软件?打工人亲测好用!

现在大家都爱看短视频和Vlog&#xff0c;要是你会剪辑视频&#xff0c;那可就牛了。不管是出去玩拍的视频&#xff0c;还是工作需要&#xff0c;都能派上用场。我就是个爱旅行、爱剪辑的发烧友&#xff0c;今天给你们推荐三款特别好用的视频剪辑软件&#xff0c;尤其是PR剪辑&a…

Android 串口数据分包处理

/* class PacketHandler { private static final byte PACKET_START 0x79; // 假设包的开始标记为0x79 private static final byte PACKET_END 0x0D; // 假设包的结束标记为0x0D private static ByteArrayOutputStream buffer new ByteArrayOutputStream();public static v…

【前端】中断请求的方式

一 使用 Axios 和取消令牌 1.步骤: 初始化取消源,创建CancelToken const source axios.CancelToken.source();传递cancelToken, 发起请求 axios.get(/api/data, {cancelToken: source.token });触发取消请求 source.cancel(操作被取消);判断错误是否由于取消请求操作引起…

Vue.js 组件化开发:父子组件通信与组件注册详解

Vue.js 组件化开发&#xff1a;父子组件通信与组件注册详解 简介&#xff1a; 在 Vue.js 的开发中&#xff0c;组件是构建应用的重要基础。掌握组件的创建与使用&#xff0c;尤其是父子组件的通信和组件的注册与命名&#xff0c;是开发中不可或缺的技能。本文将详细探讨这些内容…

【前端】CSS控制style样式失效

在CSS中&#xff0c;可以通过几种方式控制或禁用特定的style样式。 使用all: unset来重置所有可继承的属性&#xff0c;并清除所有的样式&#xff1a; .element {all: unset;} 使用inherit值来使属性获取其父元素的值&#xff1a; .element {color: inherit;font-size: inh…

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物&#xff0c;今天我们实现一下人物实现移动和跳起&#xff0c;依次点击&#xff0c;我们准备创建一个C#文件 创建好我们点击进去&#xff0c;就会跳转到我们的Vision Studio&#xff0c;然后输入这些代码 using UnityEngine;public class M…

Vue 使用接口返回的背景图片和拼图图片进行滑动拼图验证

一、背景 前两天发了一篇 vue-monoplasty-slide-verify 滑动验证码插件使用及踩坑_vue-monoplasty-slide-verify 引用后不显示-CSDN博客 这两天项目又需要通过接口校验&#xff0c;接口返回了背景图片和拼图图片&#xff0c;于是在网上找了一篇帖子&#xff0c;vue 图片滑动…

Apache Ignite 在处理大规模数据时有哪些优势和局限性?

Apache Ignite 在处理大规模数据时的优势和局限性可以从以下几个方面进行分析&#xff1a; 优势 高性能&#xff1a;Ignite 利用内存计算的优势&#xff0c;实现了极高的读写性能&#xff0c;通过分布式架构&#xff0c;它可以将数据分散到多个节点上&#xff0c;从而实现了并…