Jquery + dom-to-image 无损打印页面内容、保留页面样式

  1. 装插件
    jqueryyarn add jquery
    dom-to-imageyarn add dom-to-image

  2. 把jQuery.print.js 依赖包放到项目里

import $ from 'jquery';

function getjQueryObject(string) {
  // Make string a vaild jQuery thing
  let jqObj = $("");
  try {
    jqObj = $(string)
      .clone();
  } catch (e) {
    jqObj = $("<span />")
      .html(string);
  }
  return jqObj;
}

function printFrame(frameWindow, content, options) {
  // Print the selected window/iframe
  let def = $.Deferred();
  try {
    frameWindow = frameWindow.contentWindow || frameWindow.contentDocument || frameWindow;
    let wdoc = frameWindow.document || frameWindow.contentDocument || frameWindow;
    if(options.doctype) {
      wdoc.write(options.doctype);
    }
    wdoc.write(content);
    wdoc.close();
    let printed = false;
    let callPrint = function () {
      if(printed) {
        return;
      }
      // Fix for IE : Allow it to render the iframe
      frameWindow.focus();
      try {
        // Fix for IE11 - printng the whole page instead of the iframe content
        if (!frameWindow.document.execCommand('print', false, null)) {
          // document.execCommand returns false if it failed -http://stackoverflow.com/a/21336448/937891
          frameWindow.print();
        }
        // focus body as it is losing focus in iPad and content not getting printed
        $('body').focus();
      } catch (e) {
        frameWindow.print();
      }
      frameWindow.close();
      printed = true;
      def.resolve();
    }
    // Print once the frame window loads - seems to work for the new-window option but unreliable for the iframe
    $(frameWindow).on("load", callPrint);
    // Fallback to printing directly if the frame doesn't fire the load event for whatever reason
    setTimeout(callPrint, options.timeout);
  } catch (err) {
    def.reject(err);
  }
  return def;
}

function printContentInIFrame(content, options) {
  let $iframe = $(`${options.iframe  }`);
  let iframeCount = $iframe.length;
  if (iframeCount === 0) {
    // Create a new iFrame if none is given
    $iframe = $('<iframe height="0" width="0" border="0" wmode="Opaque"/>')
      .prependTo('body')
      .css({
        position: "absolute",
        top: -999,
        left: -999
      });
  }
  let frameWindow = $iframe.get(0);
  return printFrame(frameWindow, content, options)
    .done(() => {
      // Success
      setTimeout(() => {
        // Wait for IE
        if (iframeCount === 0) {
          // Destroy the iframe if created here
          $iframe.remove();
        }
      }, 1000);
    })
    .fail((err) => {
      // Use the pop-up method if iframe fails for some reason
      console.error("Failed to print from iframe", err);
      printContentInNewWindow(content, options);
    })
    .always(() => {
      try {
        options.deferred.resolve();
      } catch (err) {
        console.warn('Error notifying deferred', err);
      }
    });
}

function printContentInNewWindow(content, options) {
  // Open a new window and print selected content
  let frameWindow = window.open();
  return printFrame(frameWindow, content, options)
    .always(() => {
      try {
        options.deferred.resolve();
      } catch (err) {
        console.warn('Error notifying deferred', err);
      }
    });
}

function isNode(o) {
  /* http://stackoverflow.com/a/384380/937891 */
  return !!(typeof Node === "object" ? o instanceof Node : o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
}
$.print = $.fn.print = function () {
  // Print a given set of elements
  let options, $this, self = this;
  // console.log("Printing", this, arguments);
  if (self instanceof $) {
    // Get the node if it is a jQuery object
    self = self.get(0);
  }
  if (isNode(self)) {
    // If `this` is a HTML element, i.e. for
    // $(selector).print()
    $this = $(self);
    if (arguments.length > 0) {
      options = arguments[0];
    }
  } else if (arguments.length > 0) {
      // $.print(selector,options)
      $this = $(arguments[0]);
      if (isNode($this[0])) {
        if (arguments.length > 1) {
          options = arguments[1];
        }
      } else {
        // $.print(options)
        options = arguments[0];
        $this = $("html");
      }
    } else {
      // $.print()
      $this = $("html");
    }
  // Default options
  let defaults = {
    globalStyles: true,
    mediaPrint: false,
    stylesheet: null,
    noPrintSelector: ".no-print",
    iframe: true,
    append: null,
    prepend: null,
    manuallyCopyFormValues: true,
    deferred: $.Deferred(),
    timeout: 750,
    title: null,
    doctype: '<!doctype html>'
  };
  // Merge with user-options
  options = $.extend({}, defaults, (options || {}));
  let $styles = $("");
  if (options.globalStyles) {
    // Apply the stlyes from the current sheet to the printed page
    $styles = $("style, link, meta, base, title");
  } else if (options.mediaPrint) {
    // Apply the media-print stylesheet
    $styles = $("link[media=print]");
  }
  if (options.stylesheet) {
    // Add a custom stylesheet if given
    $styles = $.merge($styles, $(`<link rel="stylesheet" href="${  options.stylesheet  }">`));
  }
  // Create a copy of the element to print
  let copy = $this.clone();
  // Wrap it in a span to get the HTML markup string
  copy = $("<span/>")
    .append(copy);
  // Remove unwanted elements
  copy.find(options.noPrintSelector)
    .remove();
  // Add in the styles
  copy.append($styles.clone());
  // Update title
  if (options.title) {
    let title = $("title", copy);
    if (title.length === 0) {
      title = $("<title />");
      copy.append(title);
    }
    title.text(options.title);
  }
  // Appedned content
  copy.append(getjQueryObject(options.append));
  // Prepended content
  copy.prepend(getjQueryObject(options.prepend));
  if (options.manuallyCopyFormValues) {
    // Manually copy form values into the HTML for printing user-modified input fields
    // http://stackoverflow.com/a/26707753
    copy.find("input")
      .each(function () {
        let $field = $(this);
        if ($field.is("[type='radio']") || $field.is("[type='checkbox']")) {
          if ($field.prop("checked")) {
            $field.attr("checked", "checked");
          }
        } else {
          $field.attr("value", $field.val());
        }
      });
    copy.find("select").each(function () {
      let $field = $(this);
      $field.find(":selected").attr("selected", "selected");
    });
    copy.find("textarea").each(function () {
      // Fix for https://github.com/DoersGuild/jQuery.print/issues/18#issuecomment-96451589
      let $field = $(this);
      $field.text($field.val());
    });
  }
  // Get the HTML markup string
  let content = copy.html();
  // Notify with generated markup & cloned elements - useful for logging, etc
  try {
    options.deferred.notify('generated_markup', content, copy);
  } catch (err) {
    console.warn('Error notifying deferred', err);
  }
  // Destroy the copy
  copy.remove();
  if (options.iframe) {
    // Use an iframe for printing
    try {
      printContentInIFrame(content, options);
    } catch (e) {
      // Use the pop-up method if iframe fails for some reason
      console.error("Failed to print from iframe", e.stack, e.message);
      printContentInNewWindow(content, options);
    }
  } else {
    // Use a new window for printing
    printContentInNewWindow(content, options);
  }
  return this;
};
  1. 页面上使用
import { h } from 'preact';
import { Button } from 'antd';
import { useEffect, useState } from "preact/hooks";
import $ from 'jquery';
import './jQuery.print';
import domtoimage from 'dom-to-image';

const Printer = () => {
	const [imgUrl, setImgUrl] = useState('');
	
	useEffect(() => {
		imgUrl && $('#printImg').print()
	}, [imgUrl]);

	const JQ_Print = () => {
		const DOM = document.querySelector('#printContent');

		// JPEG和PNG都是有损图片,SVG和原图一样清晰
		domtoimage.toSvg(DOM).then((dataUrl) => {
			setImgUrl(dataUrl);
		});
	}
	
	return (
		<div>
			<Button type="primary" onClick={JQ_Print}>
				打印预览
			</Button>

			<div>
				<div id="printContent">
					{/* 登记表 */}
					<section>...</section>

					{/* 回执单 */}
					<section>...</section>
				</div>

				<img
					id="printImg"
					style={{ position: 'absolute', left: 0, top: 0, zIndex: -1 }}
					src={imgUrl}
					alt="用于打印的图片"
				/>
			</div>
		</div>
	)
}

export default Printer;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们需要创建一个 Spring Boot 项目,并添加以下依赖: ```xml <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Mybatis Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <!-- MySQL Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> <!-- JSP and JSTL --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!-- Bootstrap and jQuery --> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>5.0.0-beta3</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency> ``` 接着,我们需要配置 MySQL 数据库连接。在 `application.properties` 文件中添加以下配置: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/message_board?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ``` 其中,`message_board` 是我们新建的数据库名。 接下来,我们需要定义留言实体类 `Message`: ```java @Data @TableName("message") public class Message { @TableId(type = IdType.AUTO) private Long id; private String name; private String content; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; } ``` 使用 `@TableName` 注解指定表名,使用 `@TableId` 注解指定主键。 接着,我们需要定义留言 DAO 接口 `MessageMapper`: ```java public interface MessageMapper extends BaseMapper<Message> { } ``` 继承 `BaseMapper` 接口即可自动获得 CRUD 操作。 然后,我们需要定义留言服务实现类 `MessageServiceImpl`: ```java @Service public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService { } ``` 继承 `ServiceImpl` 类即可自动获得 CRUD 操作的实现。 接下来,我们需要定义留言控制器 `MessageController`: ```java @Controller public class MessageController { @Autowired private MessageService messageService; @GetMapping("/") public String index(Model model) { List<Message> messages = messageService.list(); model.addAttribute("messages", messages); return "index"; } @PostMapping("/add") public String add(Message message) { message.setCreateTime(new Date()); messageService.save(message); return "redirect:/"; } } ``` 使用 `@Autowired` 注解自动注入留言服务实现类。`index` 方法用于展示留言列表,`add` 方法用于添加留言。 最后,我们需要编写留言页面 `index.jsp`: ```jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html> <html> <head> <title>留言板</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="/webjars/bootstrap/5.0.0-beta3/css/bootstrap.min.css" rel="stylesheet"> <script src="/webjars/jquery/3.5.1/jquery.min.js"></script> <script src="/webjars/bootstrap/5.0.0-beta3/js/bootstrap.bundle.min.js"></script> </head> <body> <div class="container pt-5"> <div class="row"> <div class="col-md-8"> <h1>留言板</h1> <hr> <ul class="list-unstyled"> <c:forEach items="${messages}" var="message"> <li> <h4>${message.name}</h4> <p>${message.content}</p> <p class="text-muted">${message.createTime}</p> </li> </c:forEach> </ul> </div> <div class="col-md-4"> <h2>添加留言</h2> <hr> <form action="/add" method="post"> <div class="mb-3"> <label for="name" class="form-label">姓名</label> <input type="text" class="form-control" id="name" name="name"> </div> <div class="mb-3"> <label for="content" class="form-label">内容</label> <textarea class="form-control" id="content" name="content" rows="5"></textarea> </div> <button type="submit" class="btn btn-primary">提交</button> </form> </div> </div> </div> </body> </html> ``` 使用 Bootstrap 和 jQuery 实现样式和交互效果。 最后,启动项目并访问 http://localhost:8080/ 即可看到留言板页面

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值