编辑
2023-09-18
我当开发
00

目录

1. 需要解决的问题
1.1 html2canvas 本身的跨域
1.2 溢出和滚动条
1.3 样式的修改
1.4 避免前台遮挡
1.5 增加水印
2 源码
2.1 outputimg 看注释就行了
2.2 watermark.js 水印

因为特定场景,想到使用 html2canvas 给Grid导出图片,感觉比导出Excel好使一些,这里忽略了Grid的横向滚动条,遇见的可以作为参考,导出的效果还是不错的

1. 需要解决的问题

1.1 html2canvas 本身的跨域

如果直接使用 html2canvas 导出 F.ui.Grid.el 会出现跨域问题,滚动条问题,样式错位问题 等;所以还是采用 Wrapper 或者copy 、shadow 的方式,即复制 F.ui.Grid.el 放到新的div中,再导出;

1.2 溢出和滚动条

还有一个问题是滚动条,html2canvas 也会截取滚动条,如果溢出,那导出就看不见了,这里因为数据本身不会出现横向滚动条,而且没有分页,所以隐藏横向滚动条,纵向高度百分百以显示全部;

1.3 样式的修改

注意在复制后对 Wrapper 中的Grid进行修饰调整,比如有的列需要改为换行(不然挡上也显示不出来),取消选中的行,删除没用的按钮,等;

1.4 避免前台遮挡

新增的容器 Wrapper 元素需要实实在在新增到document.body 中,不能遮挡原始的 Grid 否则会很奇怪,这里使用 translateY 进行偏移,直接偏移一个Grid的高度,就挡不上了,因为没有Y的滚动条,所以看不出来对于前台是无感的;

1.5 增加水印

后来有个需求是增加水印,因为html2canvas 不支持 opacity 所以不能使用 opacity 控制水印,应该使用 canvas 这里找到了一个插件一并放出;

2 源码

2.1 outputimg 看注释就行了

js
/**导出图片 */ function outputimg() { const divElement = document.getElementById('Grid1'); // 创建一个新的div元素,避免滚动条 const screenshotWrapper = document.createElement('div'); screenshotWrapper.style.overflow = 'hidden'; screenshotWrapper.style.height = '100%'; screenshotWrapper.style.width = '100%'; screenshotWrapper.style.transform = `translateY(${divElement.offsetHeight}px)`;//偏移 以不显示 // 创建一个新的div元素,用于容纳截图内容 const screenshotContent = document.createElement('div'); screenshotContent.style.width = '100%'; // 将原始Grid的内容复制到新的div元素中 screenshotContent.innerHTML = divElement.innerHTML; // 将新的div元素添加到截图容器中 screenshotWrapper.appendChild(screenshotContent); //复制之后就可以对Wrapper中的Grid进行操作 //解决滚动条的问题 Grid原始的高度直接不要 $(screenshotContent).find(`.f-panel-body`).height(`unset`); $(screenshotContent).find(`.f-grid-bodyct`).height(`unset`); //选中的和激活的行样式都删除 $(screenshotContent).find(`.f-grid-row-selected`).removeClass(`f-grid-row-selected`); $(screenshotContent).find(`.f-state-active`).removeClass(`f-state-active`); //删除按钮或其他 $(screenshotContent).find(`.btn`).remove(); //这里做了某一列的换行 $(screenshotContent).find(`[data-columnid="MB003"] .f-grid-cell-inner`).css({ "whiteSpace": "normal", "wordBreak": "break-all" }); //添加到body中 document.body.appendChild(screenshotWrapper); //增加水印 new watermark({ text: `${thisusername} ${thisdate}`, //水印内容 render: screenshotContent, }); // 使用html2canvas进行截图操作 html2canvas(screenshotWrapper, { useCORS: true }).then(canvas => { // 创建一个新的图片元素 //const image = new Image(); //image.src = canvas.toDataURL('image/png'); // 将图片元素添加到页面中 //document.body.appendChild(image); const dataURL = canvas.toDataURL('image/png'); // 创建一个虚拟的下载链接 const downloadLink = document.createElement('a'); downloadLink.href = dataURL; downloadLink.download = '导出图片.png'; // 触发点击事件进行下载 downloadLink.click(); $(screenshotWrapper).remove(); }); }

2.2 watermark.js 水印

(function (window) { /** * js水印插件 * 自动在body底部生成一个水印 * auth:zhangdaren * date:20190218 * version: v1.0 * * */ var canvas = null; var setting = { render: document.body, text: "水印测试", //水印内容,将来支持数组和图片 fontSize: "24", //字体大小 color: "#000", //水印字体颜色 opacity: 0.1, //水印透明度 rotate: 20, //水印旋转角度 spaceX: 10, //间隔 spaceY: 10, //间隔 }; var ww; //屏幕宽度 var wh; //屏幕高度 var ctx; function watermark(option) { return new watermark.prototype.init(option); } watermark.prototype = { constructor: watermark, init: function (option) { if (option && Object.keys(option).length > 0) { // setting.text = option.text; setting.fontSize = option.fontSize || setting.fontSize; setting.color = option.color || setting.color; setting.opacity = option.opacity || setting.opacity; setting.rotate = option.rotate || setting.rotate; setting.spaceX = option.spaceX || setting.spaceX; setting.spaceY = option.spaceY || setting.spaceY; setting.render = option.render || setting.render; } ww = setting.render.clientWidth; wh = setting.render.clientHeight; // canvas = document.createElement("canvas"); canvas.style = "position:absolute; z-index:0; width:100%;height:100%;left:0;top:0"; canvas.setAttribute("width", ww); canvas.setAttribute("height", wh); setting.render.append(canvas); ctx = canvas.getContext("2d"); //渲染 watermark.prototype.render(); }, render() { watermark.prototype.clear(); // ctx.font = setting.fontSize + "px Calibri"; ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; ctx.fillStyle = setting.color; ctx.globalAlpha = setting.opacity; //这里是设置全局的透明度 //获取文本宽高 var txtWidth = ctx.measureText(setting.text).width; //单个文字宽高 var singleTxtHeight = ctx.measureText("鹏").width; //横向数量,这里加2是为了补全一些情况 var columnNum = parseInt(ww / txtWidth + 2); //文字的高度,与旋转的角度有关 var txtHeight = Math.abs(singleTxtHeight * Math.sin(setting.rotate * Math.PI / 180) * setting.text.length); // * setting.text.length; //行数 var rowNum = parseInt(wh / txtHeight); for (var i = 0; i < rowNum; i++) { var y = (txtHeight + setting.spaceY) * i; for (var j = 0; j < columnNum; j++) { var x = (txtWidth + setting.spaceX) * j; //保存上次状态 ctx.save(); //旋转canvas rotateContext(ctx, x, y, -setting.rotate); ctx.fillText(setting.text, x, y); //回到上次状态 //用于重置canvas的旋转 ctx.restore(); } } }, clear() { ctx.clearRect(0, 0, ww, wh); } }; //确保是以(x,y)为中心进行旋转,而不是简单的以画布原点旋转 function rotateContext(ctx, x, y, degree) { ctx.translate(x, y); ctx.rotate(degree * Math.PI / 180); ctx.translate(-x, -y); } function onResize() { //重新获取window宽高 ww = setting.render.clientWidth; wh = setting.render.clientHeight; //重新设置canvas宽高 canvas.setAttribute("width", ww); canvas.setAttribute("height", wh); //重绘 watermark.prototype.clear(); watermark.prototype.render(); } window.onresize = function () { throttle(onResize, window); } //函数节流 function throttle(method, context) { clearTimeout(method.tId); method.tId = setTimeout(function () { method.call(context); }, 500); } window.watermark = watermark; })(window);

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:没想好

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!