在这里插入图片描述

📋前言

今天久违的更新一下关于 Vue 的文章了,本篇文章是基于 Vue3 + Node.js + ElementPlus 的实战项目分享,实战内容包括有打印插件 Print.js 的使用,以及关于 ElementPlus 中的 el-table 与 el-pagination 的深入使用。本次项目以文章(axios 实战进阶练习——基于 Vue3 + Node.js + ElementPlus 实现的联系人列表管理后台)中的项目为模板进行改动和编写。


🎯关于 Print.js

在使用 Print.js 插件之前,我们可以通过下面的链接先了解和认识一下这个 JavaScript 插件。
官方地址Print.js - Javascript library for HTML elements, PDF and image files printing.
GitHub地址GitHub - crabbly/Printjs: A tiny javascript library to help printing from the web.
在这里插入图片描述如何认识和快速上手 Print.js,我们可以从官网的内容开始阅读,在官网中有很详细的介绍和使用例子,虽然是英文版的。Print.js 打印插件包括了 PDF 打印、HTML 打印、JSON 打印、图像打印等,这篇文章主要分享的 PDF 打印的实战,其中在使用过 Print.js 之后,对于这几种打印的类型,其实都是差不多的,主要区别还是参数配置问题。接下来就简单介绍一下这几种打印的类型。

🧩PDF 打印

Print.js 主要是为了帮助我们直接在应用程序中打印 PDF 文件,无需离开界面,也不使用嵌入。对于用户不需要打开或下载 PDF 文件,而只需要打印它们的独特情况。

例如,当用户请求打印在服务器端生成的报表时,这很有用的一种情况。这些报告以 PDF 文件的形式发回。在打印这些文件之前,无需打开它们。Print.js 提供了一种在我们的应用程序中打印这些文件的快速方法。

❗注意:PDF 文件必须从托管应用的同一网域提供。Print.js 在打印文件之前使用 iframe 加载文件,因此,它受到同源策略的限制。这有助于防止跨站点脚本 (XSS) 攻击。(关于这点也是实际项目中出现的一个问题)
在这里插入图片描述

 <button type="button" onclick="printJS('docs/printjs.pdf')">
    Print PDF
 </button>

在这里插入图片描述

 <button type="button" onclick="printJS({printable:'docs/xx_large_printjs.pdf', type:'pdf', showModal:true})">
    Print PDF with Message
 </button>

在这里插入图片描述

 <button type="button" onclick="printJS({printable: base64, type: 'pdf', base64: true})">
    Print PDF with Message
 </button>

🧩网页(HTML)打印

有时我们只想打印HTML页面的选定部分,这可能很棘手。使用 Print.js,我们可以轻松传递要打印的元素的 id。该元素可以是任何标记,只要它具有唯一的 id。图书馆将尝试非常接近它在屏幕上的外观进行打印,同时,它将为其创建打印机友好的格式。
在这里插入图片描述

<form method="post" action="#" id="printJS-form">
    ...
 </form>

 <button type="button" onclick="printJS('printJS-form', 'html')">
    Print Form
 </button>

在这里插入图片描述

<button type="button" onclick="printJS({ printable: 'printJS-form', type: 'html', header: 'PrintJS - Form Element Selection' })">
    Print Form with Header
 </button>

🧩图像打印

Print.js 可用于通过传递图像 URL 快速打印页面上的任何图像。当您使用低分辨率版本的图像在屏幕上有多个图像时,这可能很有用。当用户尝试打印所选图像时,您可以将高分辨率 url 传递给 Print.js。
在这里插入图片描述

 <img src="images/print-01.jpg" />

 printJS('images/print-01-highres.jpg', 'image')

在这里插入图片描述

printJS({printable: 'images/print-01-highres.jpg', type: 'image', header: 'My cool image header'})

 printJS({
  printable: ['images/print-01-highres.jpg', 'images/print-02-highres.jpg', 'images/print-03-highres.jpg'],
  type: 'image',
  header: 'Multiple Images',
  imageStyle: 'width:50%;margin-bottom:20px;'
 })

🧩JSON 打印

打印动态数据或 JavaScript 对象数组的简单快捷方法。
在这里插入图片描述

 someJSONdata = [
    {
       name: 'John Doe',
       email: 'john@doe.com',
       phone: '111-111-1111'
    },
    {
       name: 'Barry Allen',
       email: 'barry@flash.com',
       phone: '222-222-2222'
    },
    {
       name: 'Cool Dude',
       email: 'cool@dude.com',
       phone: '333-333-3333'
    }
 ]
 <button type="button" onclick="printJS({printable: someJSONdata, properties: ['name', 'email', 'phone'], type: 'json'})">
    Print JSON Data
 </button>

我们可以通过传递一些自定义 css 来设置数据网格的样式:

 <button type="button" onclick="printJS({
	    printable: someJSONdata,
	    properties: ['name', 'email', 'phone'],
	    type: 'json',
	    gridHeaderStyle: 'color: red; border: 2px solid #3971A5;',
	    gridStyle: 'border: 2px solid #3971A5;'
	})">
    Print JSON Data
 </button>

我们可以自定义发送对象数组的表头文本:

 <button type="button" onclick="printJS({
	    printable: someJSONdata,
	    properties: [
		{ field: 'name', displayName: 'Full Name'},
		{ field: 'email', displayName: 'E-mail'},
		{ field: 'phone', displayName: 'Phone'}
	    ],
	    type: 'json'
        })">
    Print with custom table header text
 </button>

JSON、HTML 和 Image print 可以接收原始 HTML 标头:

<button type="button" onclick="printJS({
		printable: someJSONdata,
		type: 'json',
		properties: ['name', 'email', 'phone'],
		header: '<h3 class="custom-h3">My custom header</h3>',
		style: '.custom-h3 { color: red; }'
	  })">
	Print header raw html
</button>

🧩下载并安装使用

可以从 GitHub 版本下载最新版本的 Print.js。(链接在上面提及过)
在这里插入图片描述
使用 npm 进行安装,请执行以下操作:

 npm install print-js --save

使用 yarn 安装:

  yarn add print-js

通过 npm 或 yarn 安装时,将库导入到项目中:

import print from 'print-js'

也可以使用在线的 CDN:

https://printjs-4de6.kxcdn.com/print.min.js
https://printjs-4de6.kxcdn.com/print.min.css

🧩相关配置

Print.js 将接受一个对象作为参数,下面表格的参数则为该对象的属性,通过控制属性值来控制打印。

参数默认值说明
printablenull文档来源:pdf或图像的url,html元素的id或json数据的对象
typePDF可打印类型。可用的打印选项包括:pdf,html,image,json和raw-html。
headernull用于HTML,Image或JSON打印的可选标头。它将放在页面顶部。此属性将接受文本或原始HTML
headerStyle‘font-weight:300;’要应用于标题文本的可选标题样式
maxWidth800最大文档宽度(像素)。根据需要更改此项。在打印HTML,图像或JSON时使用。
cssnull这允许我们传递一个或多个应该应用于正在打印的html的css文件URL。值可以是包含单个URL的字符串,也可以是包含多个URL的数组。
stylenull这允许我们传递一个字符串,该字符串应该应用于正在打印的html。
scanStylestrue设置为false时,库不会处理应用于正在打印的html的样式。使用css参数时很有用。
targetStylenull默认情况下,在打印HTML元素时,库仅处理某些样式。此选项允许您传递要处理的样式数组。例如:[‘padding-top’,‘border-bottom’]
targetStylesnull与targetStyle相同,这将处理任何一系列样式。例如:[‘border’,‘padding’],将包括’border-bottom’,‘border-top’,‘border-left’,‘border-right’,‘padding-top’等。你也可以传递[’*']来处理所有样式
ignoreElements[]接受打印父html元素时应忽略的html的id数组。
propertiesnull在打印JSON时使用。这些是对象属性名称。
gridHeaderStyle‘font-weight:bold;’打印JSON数据时网格标题的可选样式。
gridStyle‘border: 1px solid lightgray; margin-bottom: -1px;’打印JSON数据时网格行的可选样式
repeatTableHeadertrue在打印JSON数据时使用。设置为时false,数据表标题仅显示在第一页中。
showModalnull启用此选项可在检索或处理大型PDF文件时显示用户反馈
modalMessage‘Retrieving Document…’当向用户显示的消息showModal被设定为true。
onLoadingStartnull加载PDF时要执行的功能
onLoadingEndnull加载PDF后要执行的功能
documentTitle‘Document’打印html,image或json时,它将显示为文档标题。如果用户尝试将打印作业保存为pdf文件,它也将是文档的名称。
fallbackPrintablenull打印pdf时,如果浏览器不兼容(检查浏览器兼容性表),库将在新选项卡中打开pdf。这允许您传递要打开的不同pdf文档,而不是传递给printable的原始文档。如果您在备用pdf文件中注入javascript,这可能很有用。
onPdfOpennull打印pdf时,如果浏览器不兼容(检查浏览器兼容性表),库将在新选项卡中打开pdf。可以在此处传递回调函数,这将在发生这种情况时执行。在您想要处理打印流程,更新用户界面等的某些情况下,它可能很有用。
onPrintDialogClosenull关闭浏览器打印对话框后执行回调功能
onErrorerror => throw error发生错误时要执行的回调函数。
base64false在打印作为base64数据传递的PDF文档时使用
honorMarginPadding(不建议使用)true这用于保留或删除正在打印的元素的填充和边距。有时这些样式设置在屏幕上很棒,但在打印时看起来很糟糕。您可以通过将其设置为false来删除它。
honorColor(不建议使用)false要以彩色打印文本,请将此属性设置为true。默认情况下,所有文本都将以黑色打印。
font(不建议使用)‘TimesNewRoman’打印HTML或JSON时使用的字体
font_size(不建议使用)‘12pt’打印HTML或JSON时使用的字体大小
imageStyle (不建议使用)‘width:100%;’打印图像时使用。接受包含要应用于每个图像的自定义样式的字符串。
frameIdnullprint.js会将要打印的内容复制到一个新的Frame中,此参数是frame的id值

🎯 Vue3 中使用 Print.js 实战

接下来,我们通过业务需求和代码解析来分享一下在 Vue3 中使用 Print.js 的实战。首先我们来讲一下需求,非常简单,就是某个表格或列表的打印按钮,然后页面调起打印窗口,打印完成就删除这条打印数据。不往深入的讲,我们不谈数据来源,以及如何添加数据到打印列表,我只要知道点击这个按钮可以打印就行了,这里我们就用 Nodejs 来写一个返回 PDF 的接口,写死一条 PDF 的数据,来模拟用户添加打印数据到打印列表,实现打印功能。

接下来我们通过代码来看看如何使用 Print.js,首先是要安装 Print.js ,上面也提及到了这个 npm 命令,这里就不重复了。安装完成之后,我们要在项目中导入 Print.js,如下图。
在这里插入图片描述
我们可以先简单写个按钮来测试一下,是否可以使用正常使用这个插件。

 <button type="button" onclick="printJS('https://xxx.com/P020210715514554764187.pdf')">Print PDF</button>

上面这段代码,是打印 PDF 的一个简单例子,上面我们也说到,打印 PDF 文件时,PDF 文件必须从托管应用的同一网域提供,受到同源策略的限制。这有助于防止跨站点脚本 (XSS) 攻击。所以我们要确保这个 PDF 与项目是在同一个域(比如说 PDF 和项目都在 https://xxx.com 这个域名的服务器上面),如果不一样的话会出现跨域的情况。
在这里插入图片描述
上面图片是官网的 example 的例子,点击 Print PDF 那个按钮后,会弹出打印的窗口如上图所示。下面则是我在本地项目使用 Print.js 的例子截图。
在这里插入图片描述
我们可以看到出现了跨域的情况,是因为这个在线的 PDF (这里就不提供这个 PDF 链接,读者可以用自己的在线 PDF 来测试)跟我本地跑的 Vue 项目不是同一个网域。因此我们在后台返回获取到的 PDF 路径要跟运行的项目是同一个网域。假设把 PDF 路径上传到 OSS(对象存储服务),然后项目部署在其他的服务器什么,这种情况下,是可以进行打印访问的,但是前提是在 OSS 上面设置了允许跨域。接下来看一下这段实战中的代码片段,以及其功能的解析。

const printdelete = (row) => {
  ElMessage({
    message: "正在加入打印",
    grouping: true,
    type: "success",
  });
  printJS(IMG.value + row.path);
  console.log(IMG.value + row.path);
  const params = {
    id: row.id,
  };
  instance
    .post("/xxxapi/print/delete?id=" + params.id)
    .then((res) => {
      console.log(res);
      if (res.status === 200) {
        console.log("已添加到打印!");
        ElMessage({
          message: "已添加到打印!",
          grouping: true,
          type: "success",
        });
      } else {
        ElMessage({
          message: "打印失败",
          grouping: true,
          type: "error",
        });
      }
    })
    .catch((err) => {
      ElMessage({
        message: err,
        grouping: true,
        type: "error",
      });
    });
};

这段代码就是打印实战的代码,总体思路就是,通过后端返回的 PDF 路径,然后拼接好 OSS 的路径,在之后使用 printJS 进行打印,最后打印成功后调用删除打印列表的接口,删除刚刚打印完的打印列表数据,其他就是是一些交互操作,打印前后的消息栏。

接下来我们具体看到代码,从上往下,首先这个函数接收一个参数 row,这个参数的来源是 el-table 中每一行的数据信息,比如说打印列表有打印文件的名称,发起人,打印文件的创建时间等等,其中不在列表显示的 PDF 路径是参数 row 中尤为重要的数据。我们可以看到代码中 printJS(IMG.value + row.path); 的这段代码,其中 IMG.value 是 OSS 的路径,然后 row.path 就是刚刚所说的在列表没有显示的 PDF 路径,二者拼接起来就是一个完整打印路径,通过调用 printJS 即可实现打印。接着往下看,调起打印窗口,打印完成,接下来就是删除这条打印完的打印数据,通过请求删除的接口(这段代码 .post(“/xxxapi/print/delete?id=” + params.id)),其中代码中的 instance 是指封装的 axios.create,这样写方便后续多次调用 axios.create。

总体流程就是在函数内部,首先使用ElMessage方法显示一个成功的消息,提示正在加入打印。然后使用 printJS 方法打印 IMG.value + row.path ,并在控制台输出该路径。接下来,创建一个包含 row.id 的 params 对象。接着,使用 instance 发送一个 POST 请求到 /xxxapi/print/delete?id= 加上 params.id 作为参数的 URL。如果请求成功(状态码为 200),在控制台输出响应结果,并显示一个成功的消息。否则,显示一个失败的消息。如果发生错误,会在控制台输出错误,并显示一个错误的消息。


🎯Vue3 + Nodejs + Print.js 模拟打印实战案例

通过上面的基础学习和实战分享,我们对 Print.js 有了一定的了解,通过上手实例和项目分享的内容也可以快速 Print.js 了。接下来分享一个简单的实战案例,来巩固和总结一下前面文章提及的内容。
在这里插入图片描述
首先,我们使用 Nodejs 写一个服务,把本地的 PDF 部署在 http://localhost:8080/ 上面,在使用 Print.js 确保 PDF 和 Vue 项目都在同一个网域下,避免出现跨域的情况。接下来,我们一起来看一下 Nodejs 的代码。

const express = require('express');
const app = express();
const path = require('path');
const fs = require('fs');
const {
    createProxyMiddleware
} = require('http-proxy-middleware');

// 设置端口号
const port = 8080;

// 加载静态资源
// app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname)));

// 处理下载请求
app.get('/api/getPdfLink', (req, res) => {
    // 构造文件绝对路径
    //   const filePath = path.join(__dirname, 'P020221111501862950279.pdf');
    const pdfPath = 'http://localhost:8080/P020221111501862950279.pdf';
    console.log(`File path: ${pdfPath}`);

    // 返回文件路径
    res.send({
        link: pdfPath
    });
});

// 反向代理到 Vue 项目
app.use(
    '/',
    createProxyMiddleware({
        target: 'http://localhost:8080',
        changeOrigin: true,
    })
);

// 启动服务
app.listen(port, () => {
    console.log(`Server listening at http://localhost:${port}/api/getPdfLink`);
});

首先创建 app.js 作为项目的入口文件,后续只要 node app 即可运行服务,然后安装所需的配置文件,如下命令。

npm install express		// 安装 Express 框架

因为Vue 项目已经占用了 8080 端口,为了确保 Nodejs 服务也监听在同一个端口上,以保持相同的域名,我们可以尝试使用反向代理来实现这一目的,安装命令如下。

npm install http-proxy-middleware	// 安装反向代理

安装好这些配置后,我们看具体代码的功能。这个程序的主要目的就是写一个接口返回 PDF 路径,然后前端调用这个接口获取到 PDF 的路径,然后实现打印功能。接下来简单分析一下这段代码。

  • 设置端口号为 8080:const port = 8080;
  • 加载静态资源:app.use(express.static(path.join(__dirname)));。这里使用 Express 的 express.static 中间件来加载静态资源。path.join(__dirname) 表示将当前目录作为静态资源所在的根目录。这意味着 PDF 文件应该放在服务器启动的根目录中,如下图。
    在这里插入图片描述
  • /api/getPdfLink 接口:当客户端通过 /api/getPdfLink 路径发送 GET 请求时,服务器会返回一个包含 PDF 文件路径的 JSON 响应。在这个例子中,PDF 文件的路径是硬编码的,为 http://localhost:8080/P020221111501862950279.pdf。
app.get('/api/getPdfLink', (req, res) => {
    const pdfPath = 'http://localhost:8080/P020221111501862950279.pdf';
    console.log(`File path: ${pdfPath}`);
    res.send({ link: pdfPath });
});
  • 反向代理到 Vue 项目:这部分代码将所有对根路径 / 的请求反向代理到目标地址为 http://localhost:8080 的服务器。这通常用于将 Express 服务器和 Vue 项目集成在一起,实现前后端的联合开发。
app.use(
    '/',
    createProxyMiddleware({
        target: 'http://localhost:8080',
        changeOrigin: true,
    })
);
  • 启动服务器:最后,通过调用 app.listen 方法,启动服务器并监听指定的端口号。
app.listen(port, () => {
    console.log(`Server listening at http://localhost:${port}/api/getPdfLink`);
});

🧩启动 Nodejs 服务

接下来通过 node app 启动服务,并且测试一下接口是否可以获取到数据。
在这里插入图片描述
直接在浏览器访问 http://localhost:8080/api/getPdfLink。
在这里插入图片描述
然后再访问 http://localhost:8080/P020221111501862950279.pdf。
在这里插入图片描述
到此 Nodejs 服务启动没用问题,接下来我们运行一下 Vue 项目。

🧩启动 Vue 项目

npm run serve 直接启动项目。
在这里插入图片描述
页面非常简单,就只有一个按钮。通过下图控制台输出的结果,可以说明成功调用接口,返回了参数。
在这里插入图片描述
然后我们点击这个按钮,试一下能不能成功调起打印窗口呢。
在这里插入图片描述
最后成功调起的了打印窗口,运行成功,到此项目的主流程已经完成了。下面是这个页面的代码。

<template>
  <div class="contact-list" id="#printJS-HTML'">
    <!-- 标题 -->
    <el-row justify="center">
      <button type="button" @click="printPDF">Print PDF</button>
    </el-row>
  </div>
</template>

<script setup>
// import { ElMessage, ElMessageBox } from "element-plus";
import printJS from "print-js";
import { ref, onMounted } from "vue";
import axios from "axios";
import Http from "@/service/http";
// axios默认数据
// const instance = axios.create({
//   baseURL: "http://localhost:8080",
//   timeout: 10000,
// });

// 在组件挂载完毕后调用 refreshList 函数
onMounted(() => {
  refreshList();
});

const pdflink = ref();
const refreshList = async () => {
  let res = await Http.getPdfLink();
  pdflink.value = res.link;
  console.log(res);
  console.log(res.link);
};

const printPDF = () => {
  printJS(pdflink.value);
};
</script>

<style scoped>
.contact-list {
  max-width: 800px;
  margin: auto;
  padding: 20px;
}
</style>

如果需要完整代码或者项目的读者,可以私信我或者添加我的联系方式获取,如收到消息会第一时间回复。


📝最后

到此就是 Vue 实战篇——打印插件 Print.js 的使用(Vue3 + Nodejs + Print.js 实战)以及 el-table 与 el-pagination 的深入使用(上)的全部内容了,通过这篇文章,我们可以多学一招,学会使用 Print.js 插件打印 PDF 文件。以及通过 Vue3 + Nodejs + Print.js 实战,我们可以加深对该插件的熟悉程度,其实该实战的难点是 Nodejs 服务的编写,但这不是我们所要深究的,这只是解决跨域问题的一个前提,最主要是体验和上手过一遍打印的流程。通过接口获取到 PDF 文件的路径,然后在项目中使用 Print.js 插件的 printJS 方法,把获取到的路径传入这个方法,然后调起打印窗口,最后完成打印。

除此之外,关于该项目的实战延申,还有关于 el-table 与 el-pagination 的内容,这些内容会在《Vue3 开发实战分享——打印插件 Print.js 的使用(Vue3 + Nodejs + Print.js 实战)以及 el-table 与 el-pagination 的深入使用(下)》介绍和分享,敬请期待。
在这里插入图片描述

🔥文末送书

🧩编辑推荐

(1)实用性强:本书的案例是基于真实的企业级项目需求而开发的,读者可通过学习本 书,掌握实际项目开发中的技巧和方法。
(2)实用性强:本书的案例是基于真实的企业级项目需求而开发的,读者可通过学习本 书,掌握实际项目开发中的技巧和方法。
(3)互动性强:本书赠送配套的微课视频约164集,读者可通过观看视频更好地理解代码的实现过程和实现方法。

🧩内容介绍

本书是一本实用性很强的Vue.js 3实战项目书。书中结合实际项目场景,构建了一个完整的企业级应用。全书共分13章,内容包含项目概述、Vue3项目管理、登录管理、后台主框架、图库管理、管理员管理、用户管理、商品管理、订单管理、优惠券管理、商品评论管理、分销管理和公告管理,并且讲解了这些模块的实际应用方法。同时,本书还介绍了如何使用Vite、Axios、Vue Router、Vuex等流行工具和库,以提高开发效率、提升用户体验。

🧩作者介绍

袁龙,从事Web开发、教学培训等业务,创建“锦匠特效”和“锦匠课堂”两大Web前端工具类网站,为数万前端开发者提供高效率的工作方式,轻松实现网页动画特效,目前是51CTO、CSDN等在线教育平台讲师。著有《Vue.js核心技术解析与uni-app跨平台开发实战》《Node.js从基础到项目实践(视频教学版) 》等多部著作。

在这里插入图片描述

🔥参与方式

《 Vue.js 3企业级项目开发实战》免费包邮送出 3 本!

抽奖方式:评论区随机抽取 3 位小伙伴免费送出!
参与方式:关注博主、点赞、收藏、评论区评论 “人生苦短,我学Vue!” (切记要点赞+收藏,否则抽奖无效,每个人最多评论三次!)
活动截止时间:2023-10-21 20:00:00
当当自营店购买链接http://product.dangdang.com/29621812.html
在这里插入图片描述

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐