vue使用luckysheet,引入图表chartmix,实现打印按钮功能

2023-11-17

1.下载Luckysheet源码

下载地址:https://github.com/dream-num/Luckysheet
按照下载地址提示 npm run build 打包源码,生成dist文件夹
dist文件夹下的目录

2.引入luckysheet的js文件和css文件

① 在vue项目的根目录public中新建luckysheet文件夹,然后将步骤1中的dist内的所有文件放到luckysheet中。
在这里插入图片描述

② 在vue项目的根目录public的index.html文件中引入相关js和css

    <link rel='stylesheet' href='./luckyexcel/plugins/css/pluginsCss.css' />
    <link rel='stylesheet' href='./luckyexcel/plugins/css/pluginsCss.css' />
    <link rel='stylesheet' href='./luckyexcel/plugins/plugins.css' />
    <link rel='stylesheet' href='./luckyexcel/css/luckysheet.css' />
    <link rel='stylesheet' href='./luckyexcel/assets/iconfont/iconfont.css' />
    <script src="./luckyexcel/plugins/js/plugin.js"></script>
    <script src="./luckyexcel/luckysheet.umd.js"></script>

在这里插入图片描述
③ 验证是否成功引入js和css
参考文件:https://blog.csdn.net/Lyy1991Wdl/article/details/124175868 进行验证

或者直接使用下面的代码:

<template>
  <div class="luckyexcelConstentCss" :style="{height}">
    <div id="luckysheet" class="luckyexcelCss" />
  </div>
</template>

<script>
export default {
  props: {
    height: {
      type: String,
      default: '500px'
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    init() {
      const options = {
        container: 'luckysheet', // 设定DOM容器的id
        title: 'Luckysheet Demo', // 设定表格名称
        lang: 'zh', // 设定表格语言
        plugins: ['chart'], // 图表插件使用 https://blog.csdn.net/u013355529/article/details/116133127
        showtoolbar: false, // 想要使用 showtoolbarConfig, 必须将showtoolbar设为false
        showtoolbarConfig: {
          undoRedo: true, //撤销重做,注意撤消重做是两个按钮,由这一个配置决定显示还是隐藏
          mergeCell: true, // '合并单元格'
          fillColor: true, // '单元格颜色'
          textColor: true, // '文本颜色'
          sortAndFilter: true, // '排序和筛选'
          findAndReplace: true, // '查找替换'
          chart: true, // 图表 (引入插件: https://blog.csdn.net/u013355529/article/details/116133127)
          print: true // '打印'
        }
      }

      luckysheet.create(options) // eslint-disable-line
    }
  }
}

</script>

<style scoped>
.luckyexcelConstentCss {
  margin: 0 30px;
  
}
.luckyexcelCss {
  width: 100%;
  height: 100%;
}
</style>

vue项目运行之后显示以下界面即引入成功
在这里插入图片描述

3.引入图表chartmix

将步骤1中的dist内的expendPlugins文件夹,放置到你的vue项目的根目录public中
放到public就完成了引入
验证图表插件是否引入成功
在表格中输入以下内容,并将输入的内容选中,然后点击图表按钮
在这里插入图片描述
引入成功则显示以下样式
在这里插入图片描述

4.实现打印按钮功能

参考文献:https://blog.csdn.net/alan_ji198573/article/details/128624832
回到步骤1下载的luckysheet源码

① 找到lucksheet源码中\src\controllers\menuButton.js,修改函数:$(“#luckysheet-icon-print”).click
在这里插入图片描述
将 $(“#luckysheet-icon-print”).click 函数的内容用以下代码替换掉

//print
$("#luckysheet-icon-print").click(function(){
    //获取页面的按钮控件,在点击菜单时触发页面按钮点击事件
    if($("#printPreviewBtn"))
    {
        $("#printPreviewBtn").click();
    }
    //将源项目代码全部注释,只用上面的代码
}

在这里插入图片描述

② 新增getScreenshotNew函数,找到luckysheet源码中的src\global\api.js
在这里插入图片描述

新增getScreenshotNew函数,即将以下代码复制到api.js中

/**
 * 将选中区域进行截图,截图完成后调用指定委托函数,(修复支持插入的图片及图表截图):ALAN-JI
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,只能为单个选区;默认为当前选区
 * @param {function} action 委托执行函数,当所有绘图完成后,执行此委托函数(委托函数中可用于触发图片打印,或图片显示)
 */
export function getScreenshotNew(action, options = {}) {
    let {
        range = Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1],
    } = { ...options }
 
    if (getObjType(range) == 'string') {
        if (!formula.iscelldata(range)) {
            return tooltip.info("The range parameter is invalid.", "");
        }
 
        let cellrange = formula.getcellrange(range);
        range = {
            "row": cellrange.row,
            "column": cellrange.column
        };
    }
 
    if (getObjType(range) != 'object' || range.row == null || range.column == null) {
        return tooltip.info("The range parameter is invalid.", "");
    }
 
    let str = range.row[0],
        edr = range.row[1],
        stc = range.column[0],
        edc = range.column[1];
 
    let has_PartMC = hasPartMC(Store.config, str, edr, stc, edc);
 
    if (has_PartMC) {
        return tooltip.info('Cannot perform this operation on partially merged cells', '');
    }
 
    let visibledatarow = Store.visibledatarow;
    let visibledatacolumn = Store.visibledatacolumn;
 
    let scrollHeight, rh_height;
    if (str - 1 < 0) {
        scrollHeight = 0;
        rh_height = visibledatarow[edr];
    }
    else {
        scrollHeight = visibledatarow[str - 1];
        rh_height = visibledatarow[edr] - visibledatarow[str - 1];
    }
 
    //根据当前分辨率计算出A4纸宽度,高度(高度不用限制,默认会自动分页)
    let a4Size=calculateA4PaperSize();
    let scrollWidth, ch_width=a4Size.width;
    if (stc - 1 < 0) {
        scrollWidth = 0;
        ch_width = visibledatacolumn[edc]<a4Size.width ? visibledatacolumn[edc]:a4Size.width;
    }
    else {
        scrollWidth = visibledatacolumn[stc - 1];
        ch_width = visibledatacolumn[edc] - visibledatacolumn[stc - 1]<a4Size.width ? visibledatacolumn[edc] - visibledatacolumn[stc - 1]:a4Size.width;
    }
 
    let newCanvas = $("<canvas>").attr({
        width: Math.ceil(ch_width * Store.devicePixelRatio),
        height: Math.ceil(rh_height * Store.devicePixelRatio)
    }).css({ width: ch_width, height: rh_height });
 
    luckysheetDrawMain(scrollWidth, scrollHeight, ch_width, rh_height, 1, 1, null, null, newCanvas);
    
    let ctx_newCanvas = newCanvas.get(0).getContext("2d");
 
    //补上 左边框和上边框
    ctx_newCanvas.beginPath();
    ctx_newCanvas.moveTo(
        0,
        0
    );
    ctx_newCanvas.lineTo(
        0,
        Store.devicePixelRatio * rh_height
    );
    ctx_newCanvas.lineWidth = Store.devicePixelRatio * 2;
    ctx_newCanvas.strokeStyle = luckysheetdefaultstyle.strokeStyle;
    ctx_newCanvas.stroke();
    ctx_newCanvas.closePath();
 
    ctx_newCanvas.beginPath();
    ctx_newCanvas.moveTo(
        0,
        0
    );
    ctx_newCanvas.lineTo(
        Store.devicePixelRatio * ch_width,
        0
    );
    ctx_newCanvas.lineWidth = Store.devicePixelRatio * 2;
    ctx_newCanvas.strokeStyle = luckysheetdefaultstyle.strokeStyle;
    ctx_newCanvas.stroke();
    ctx_newCanvas.closePath();
    
    //获取插入图片的元素,并在canvas上进行绘制
    if ($('#luckysheet-image-showBoxs')) {
        var imgs = $('#luckysheet-image-showBoxs img');
        imgs.each(function (i) {
            var parent = $(this).parent().parent();
            var left = parent.css("left").replace('px', '');
            var top = parent.css("top").replace('px', '');
            var width = parent.css("width").replace('px', '');
            var height = parent.css("height").replace('px', '');
            var img = new Image()
            img.src = $(this).attr("src");
            ctx_newCanvas.drawImage(img, left, top, width, height);
        });
    }
    //获取统计图元素,并在canvas上进行绘制
    let targetDoms = document.querySelectorAll('.luckysheet-modal-dialog.luckysheet-modal-dialog-chart.luckysheet-data-visualization-chart');
    var chartCount = 0;
    if (targetDoms && targetDoms.length > 0)
    {
        repaintChartScreenshot(newCanvas,ctx_newCanvas,targetDoms,action,0,targetDoms.length);
    }
    
    if (!targetDoms || targetDoms.length == 0) {
        if (action) {
            action(newCanvas.get(0).toDataURL("image/png", 1));
        }
    }
}
 
/**
 * 递归获取所有统计图,并重绘chart到截屏图上:ALAN-JI
 * @param {object} newCanvas canvas画布元素对象
 * @param {object} ctx_newCanvas 当前画布用于绘制新图的对象
 * @param {NodeListOf} targetDoms 所有统计图Nodes集合
 * @param {function} action 委托函数,当所有绘图完成后,执行此委托函数(委托函数中可用于触发图片打印,或图片显示)
 * @param {int} index 当前统计图下标
 * @param {int} length 统计图总集合长度
 */
export function repaintChartScreenshot(newCanvas,ctx_newCanvas,targetDoms,action,index,length) {
    let targetDom = targetDoms[index];
    var left = targetDom.style.left.replace('px', '');
    var top = targetDom.style.top.replace('px', '');
    var width = targetDom.style.width.replace('px', '');
    var height = targetDom.style.height.replace('px', '');
 
    // 此处是实现滚动元素长截图的关键 start
    let copyDom = targetDom.cloneNode(true)
    copyDom.setAttribute('id', 'copyDom')  // 更改id 避免与targetDom id重复
    copyDom.style.width = targetDom.scrollWidth + 'px'
    copyDom.style.height = targetDom.scrollHeight + 'px'
    var chartCanvas = targetDom.getElementsByTagName("canvas")[0];
    var canvasToImg = new Image();
    canvasToImg.src = chartCanvas.toDataURL('image/png', 1);
    canvasToImg.style = chartCanvas.style;
    copyDom.innerHTML = copyDom.innerHTML.replace(chartCanvas.outerHTML, canvasToImg.outerHTML)
    copyDom.style.zIndex=-50
    document.querySelector('body').appendChild(copyDom);
    // 此处是实现滚动元素长截图的关键 end
 
    /* 
    *如不需要长截图,或者要截取的元素无滚动即完全显示。
    *下方要截取的元素改为targetDom,并把copyDom相关代码删除即可 
    */
    // html2canvas截屏,屏幕有滚动条时截图为空
    html2canvas(copyDom, {
        backgroundColor: "transparent",
        allowTaint: true,
        useCORS: true,
        scale: window.devicePixelRatio * 3,
        logging: false,
        imageTimeout: 15000,
        removeContainer: true,
    }).then(canvas => {
        var chartImg = new Image()
        chartImg.src = canvas.toDataURL('image/png', 1);
        document.querySelector('body').removeChild(copyDom)
        chartImg.onload = function () {
            index++;
            ctx_newCanvas.drawImage(chartImg, left, top, width, height);
            if (index >= length && action) {
                action(newCanvas.get(0).toDataURL("image/png", 1));
            }
            else
            {
                //递归调用重绘图片
                repaintChartScreenshot(newCanvas,ctx_newCanvas,targetDoms,action,index,length);
            }
        }
    });
}

/**
* 根据当前系统DPI象素计算A4纸大小:ALAN-JI
* @returns {object} width:a4宽度,height:a4高度
*/
export function calculateA4PaperSize()
{
function findFirstPositive(b, a, i, c) {
c=(d,e)=>e>=d?(a=d+(e-d)/2,0<b(a)&&(a==d||0>=b(a-1))?a:0>=b(a)?c(a+1,e):c(d,a-1)):-1
for (i = 1; 0 >= b(i);) i *= 2
return c(i / 2, i)|0
}

var dpi = findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches)
switch (dpi) {
case 72:
return { width: 598, height: 842 };
case 96:
return { width: 794, height: 1123 };
case 120:
return { width: 1487, height: 2105 };
case 150:
return { width: 1240, height: 1754 };
case 300:
return { width: 2480, height: 3508 };
default:
return { width: 794, height: 1123 };
}
}

③ 依次重复步骤1和步骤2,然后vue项目中使用 npm install vue-print-nb -D 引入 vue-print-nb 打印插件

④ 可以使用以下vue完整代码到vue项目中,测试是否打印成功

<template>
  <div class="luckyexcelConstentCss" :style="{height}">
    <el-button id="printPreviewBtn" style="display: none;" @click="printExcel()">打印预览</el-button>
    <el-button id="printExcelBtn" style="display: none;" plain
      v-print="{ id: 'print_html', popTitle: 'test111' }">打印</el-button>
    <div id="print_html" class="procedure" style="text-align: center;z-index: 0;"></div>

    <div id="luckysheet" class="luckyexcelCss" />
  </div>
</template>

<script>
import Vue from 'vue'
import Print from 'vue-print-nb'
Vue.use(Print)

export default {
  props: {
    height: {
      type: String,
      default: '500px'
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    init() {
      const options = {
        container: 'luckysheet', // 设定DOM容器的id
        title: 'Luckysheet Demo', // 设定表格名称
        lang: 'zh', // 设定表格语言
        plugins: ['chart'], // 图表插件使用 https://blog.csdn.net/u013355529/article/details/116133127
        showtoolbar: false, // 想要使用 showtoolbarConfig, 必须将showtoolbar设为false
        showtoolbarConfig: {
          undoRedo: true, //撤销重做,注意撤消重做是两个按钮,由这一个配置决定显示还是隐藏
          mergeCell: true, // '合并单元格'
          fillColor: true, // '单元格颜色'
          textColor: true, // '文本颜色'
          sortAndFilter: true, // '排序和筛选'
          findAndReplace: true, // '查找替换'
          chart: true, // 图表 (引入插件: https://blog.csdn.net/u013355529/article/details/116133127)
          print: true // '打印'
        }
      }

      luckysheet.create(options) // eslint-disable-line
    },
    async printExcel() { // 打印预览事件实现, 参考文档: https://blog.csdn.net/alan_ji198573/article/details/128624832
      this.printSheet()
    },
    printSheet() { // 打印操作:自动选中打印区域,并生成打印截图,进行打印
      document.querySelector('#print_html').style = "display:block"
      window.luckysheet.hideGridLines()
      
      let currentSelected = luckysheet.getRange() // 获取当前选中区域
      
      if (currentSelected[0] != null &&
        (currentSelected[0].row[1] - currentSelected[0].row[0] >= 1 || 
        currentSelected[0].column[1] - currentSelected[0].column[0] >= 1)) { // 如果当前选中区只是一个单元格,则认为选取无效。
        luckysheet.getScreenshotNew((imgSrc) => { // 将打印区域生成base64图片(*将生成的base64编码复制粘贴到浏览器地址框,是可以预览图片样式的),生成后执行的后续打印操作,取用匿名委托函数做为参数传入
          window.luckysheet.showGridLines()
          let $img = `<img src=${imgSrc} style="max-width: 90%;" />`
          this.$nextTick(() => {
            document.querySelector('#print_html').innerHTML = $img
          })
          document.getElementById('printExcelBtn').click()
          setTimeout(() => {
            document.querySelector('#print_html').style = "display:none"
          }, 100)
        })
      }
      else {
        
        const RowColumn = this.getPrintSheetArea() // 获取打印区域的行列
        // 因需要打印左边的边框,需重新设置第一列
        // RowColumn.column[0] = 0;
        
        luckysheet.setRangeShow(RowColumn) // 进行选区操作
        luckysheet.getScreenshotNew((imgSrc) => { // 将打印区域生成base64图片(*将生成的base64编码复制粘贴到浏览器地址框,是可以预览图片样式的),生成后执行的后续打印操作,取用匿名委托函数做为参数传入
          window.luckysheet.showGridLines()
          const $img = `<img src=${imgSrc} style="max-width: 90%;" />`
          this.$nextTick(() => {
            document.querySelector('#print_html').innerHTML = $img
          })
          document.getElementById('printExcelBtn').click()
          setTimeout(() => {
            document.querySelector('#print_html').style = "display:none"
          }, 100)
        })
      }

    },
    getPrintSheetArea() { // 获取打印区域(即表格中有内容、非空白的区域)(用row,column数组表示)
      const sheetData = luckysheet.getSheetData();
      let objRowColumn = {
        row: [0, 0], // 行
        column: [0, 0], // 列
      };
      
      sheetData.forEach((item, index) => { // * item是行、index是行索引、it是一行里的一格、itemIndex是这一格在这一行里的列索引
        item.forEach((it, itemIndex) => { // 行数
          if (it !== null) {
            if (objRowColumn.row[1] < index) {
              objRowColumn.row[1] = index; // row第二位
            }
            if (objRowColumn.column[1] < itemIndex) {
              objRowColumn.column[1] = itemIndex; // column第二位
            }
          }
        });
      });
      return objRowColumn;
    },
  }
}

</script>

<style scoped>
.luckyexcelConstentCss {
  margin: 0 30px;
}
.luckyexcelCss {
  width: 100%;
  height: 100%;
}
</style>

⑤ 选择区域点击打印
在这里插入图片描述

打印成功会弹出打印弹窗
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue使用luckysheet,引入图表chartmix,实现打印按钮功能 的相关文章

随机推荐

  • MATLAB绘制正弦函数与余弦函数的线性组合曲线

    h0 figure toolbar none position 200 150 450 350 name 实例11 x 0 pi 20 2 pi y1 sin x y2 cos x h1 stem x y1 y2 画出线性组合的图 hold
  • SQL注入——学生选课系统注入

    目录 前言 一 实验环境 二 实验步骤 1 万能密码 2 堆叠注入 3 报错注入 4 时间盲注 前言 本次实验利用教师指定的学生选课管理系统进行SQL注入 包含万能密码登录 堆叠注入 报错注入和时间盲注 一 实验环境 Windows10虚拟
  • QT 15--获取任何种类文件的某些文件属性:大小、创建时间、上次修改时间等等

    1 首先说一些 如果是mainwindow的QT工程 如果打算做自己手写ui 界面的话 该如何将自己写的内容添加到mainwindow界面呢 方法为 新建一个widget类 然后将所有零件都用布局布置好后 只需将总布局添加到widet 然后
  • KMP时间复杂度分析

    比较过程分析 比较次数 比较次数 红色 蓝色 蓝色部分是相比暴力求解 节省下的比较次数 周期 从比较次数可以看出 呈现 1 1 1 1 5 这样的周期 一个周期内的比较次数 8 周期长度 5 周期个数 n 5 比较总次数 周期个数 一个周期
  • 学成在线笔记+踩坑(10)——课程搜索、课程发布时同步索引库。

    导航 黑马Java笔记 踩坑汇总 JavaSE JavaWeb SSM SpringBoot 瑞吉外卖 SpringCloud 黑马旅游 谷粒商城 学成在线 牛客面试题 java黑马笔记 目录 1 检索模块 需求分析 1 1 全文检索介绍
  • H3 GPIO笔记

    NanoPi NEO Core最近买了一块 这个板子使用全志H3 查看H3的数据手册 把GPIO这部分做个笔记 H3有7组GPIO 如下 分别是PA PC PD PE PF PG PL 没有PB这一组 PA有22个端口 PC有19个端口 P
  • 【LeetCode题解】1475、商品折扣后的最终价格

    题目 给你一个数组 prices 其中 prices i 是商店里第 i 件商品的价格 商店里正在进行促销活动 如果你要买第 i 件商品 那么你可以得到与 prices j 相等的折扣 其中 j 是满足 j gt i 且 prices j
  • CSS动画:Transition与Animation

    本文总结CSS3中两个用来做动画的属性 一个是transition 另一个是animation 差异比较 CSS3 差异 transition 在给定的持续时间内平滑地更改属性值 从一个值到另一个值 也就是只需要指定开始与结束的参数 参数改
  • 让汽车的全景环视更智能更安全!

    随着现代汽车安全技术的进步 我们看到诸如全景环视等先进驾驶辅助 ADAS 技术成为现代汽车的新标准 本演示展示了如何通过精确的实时反射和AI来检测障碍 以提升全景环视系统的性能 让汽车驾驶更安全 尤其是 当全景环视系统内嵌Imaginati
  • cesium-添加点并且可以编辑

    完整代码
  • 05_Numpy任意行&列的删除方法(numpy.delete)

    05 Numpy任意行 列的删除方法 numpy delete 函数Numpy delete 可以删除ndarray数组中任意的行或者列 指定要删除的轴 维度 和要删除的位置 行号 列号 也可以通过切片或列表选择多个行或者列的编号 对以下的
  • 【Unity Shaders】抖音变身漫画1

    先来看一下手机拍出来的效果 我们发现有一张人像变成了卡通漫画脸 其它的只是做了一些图像处理 你可以再拍几张看一下 会发现千篇一律的大眼 小嘴有没有 你想的没错 这个是AI换脸技术 抖音特效里有很多了 把这个漫画脸再加上对图像的漫画处理 最后
  • 解读CUDA Compiler Driver NVCC - Ch.5

    前言 前面几篇文章 我们了解了NVCC的作用 nvcc编译的two stage 每个stage做了什么 怎么去选择虚拟架构和真实架构 JIT编译的原理 好处和弊端以及解决方案 本文我们将了解几个实际的nvcc编译命令 Base Notati
  • el-select中多选回显数据后没法重新选择和更改

    我用element select 多选回显的时候 回显正常 不能点击清除 不能选择改变数据 然后去搜了这篇文章文章链接 博主解释要在select标签上加一个强制渲染 如下图
  • Docker的网络模式

    目录 Docker的四种网络模式 1 Bridge 网络模式 类似于VMware的NAT模式 Bridge 网络模式介绍 bridge模式示意图 2 Host 网络模式 Host 网络模式介绍 Host模式示意图 3 Container 网
  • 【Redis】集合Set和底层实现

    文章目录 Redis 集合 Set Set简介 常用命令 应用场景 共同关注实例 整数集合 整数集合介绍 整数集合的升级 哈希表 哈希表的原理和实现 Redis中的哈希表 rehash 渐进式rehash Redis 集合 Set Set简
  • 如何用xp系统做服务器,xp系统如何做远程服务器呢

    xp系统如何做远程服务器呢 内容精选 换一换 网站的访问与云服务器的网络配置 端口通信 防火墙配置 安全组配置等多个环节相关联 任意一个环节出现问题 都会导致网站无法访问 本节操作介绍网站无法访问时的排查思路 网站无法访问怎么办 如果打开网
  • 14-5_Qt 5.9 C++开发指南_基于HTTP 协议的网络应用程序

    文章目录 1 实现高层网络操作的类 2 基于HTTP协议的网络文件下载 3 源码 3 1 可是化UI设计 3 2 mainwindow h 3 3 mainwindow cpp 1 实现高层网络操作的类 Qt 网络模块提供一些类实现 OSI
  • Synchronized的锁升级过程

    Synchronized的锁升级过程 synchronized锁升级过程 在synchronized中引入了偏向锁 轻量级锁 重量级锁之后 当前具体使用的是synchronzed中的那种类型锁 是根据线程竞争激烈程度来决定的 偏向锁 在锁对
  • vue使用luckysheet,引入图表chartmix,实现打印按钮功能

    1 下载Luckysheet源码 下载地址 https github com dream num Luckysheet 按照下载地址提示 npm run build 打包源码 生成dist文件夹 2 引入luckysheet的js文件和cs