免费开源luckysheet+luckyExcel,本地导入文件,渲染excel,公式计算,导出excel

这篇具有很好参考价值的文章主要介绍了免费开源luckysheet+luckyExcel,本地导入文件,渲染excel,公式计算,导出excel。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目需求:

本地导入excel,页面渲染excel,一键计算:根据计算逻辑求出得分回写到对应单元格,最后导出excel;

前端技术:Vue2,luckysheet,luckyExcel,exceljs,mathjs,antdv

Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。

上传下载demo:  luckysheet-demo: luckysheet-demo

用到的插件和api:

1,本地导入excel并渲染

npm下载luckysheet后通过 import 方式引入报错,官网给出了两种引入方式:CDN , 本地引入;CDN没什么说的直接引入即可,此次介绍一下本地引入;

快速上手 | Luckysheet文档

//文件上传按钮
<div> 
         <a-upload
          :file-list="fileList"
          name="file"
          :multiple="false"  //禁止多选
          :showUploadList="{showRemoveIcon: false}"  //隐藏删除文件icon
          :before-upload="handleUpload"
        >
          <a-button type="primary" class="upload">
           点击上传
          </a-button>
        </a-upload>
        <div class="uploadTip">
          只能上传xlsx文件!
        </div>
 </div>

 //渲染excel容器
 <div id="luckysheet" class="luckySheet" v-show="showLuckyExcel"></div>


//-----methods----------------------------------------------
import LuckyExcel from 'luckyexcel'; //引入LuckyExcel
//luckysheet 引入报错,官网给出了两种引入方式:CDN , 本地引入

//(1)上传文件
 handleUpload(file){     
      if(file.name.substring(file.name.length-5) === '.xlsx'){
          this.spinning = true
          this.spinningTip =  '文件上传中...'
          this.file = file;
          this.fileList = [file]; //只允许上传一个文件
          LuckyExcel.transformExcelToLucky(file, (exportJson, luckysheetfile) => {
             luckysheet.destroy();
             this.initExcel(exportJson);
          },error =>{
            this.$message.error(error)
          });
          return false;
      }else{
        this.$message.error('文件格式错误,请上传.xlsx文件!')
      }
    },

//(2)渲染excel
initExcel(exportJson) {
      //工作表保护
       exportJson.sheets.forEach(t=>{
         t.config.authority = {
          sheet: 1, 
          hintText: "您试图更改的单元格或图表位于受保护的工作表中!", 
            allowRangeList: [
        	{ sqref: '$A$2:$D$6' },//设置A2~D6为可编辑区域,其它区域不可编辑 
           ],
         }
       });
      //初始化excel
      luckysheet.create({
        container: 'luckysheet', //dom id
        showtoolbar: false,   //隐藏工具栏
        sheetFormulaBar: false,  //隐藏公式栏
        enableAddRow: false,  //隐藏新增row
        showtoolbarConfig: {
          print: false // 隐藏插件内部打印按钮
        },
        sheetRightClickConfig: {  // 工作表右键:禁用 删除,复制...
          delete: false, 
          copy: false, 
          rename: false, 
          color: false, 
          hide: false, 
          move: false, 
        },
        cellRightClickConfig: { //单元格右键配置
          paste: false, // 粘贴
          insertRow: false, // 插入行
          insertColumn: false, // 插入列
          deleteRow: false, // 删除选中行
          deleteColumn: false, // 删除选中列
          deleteCell: false, // 删除单元格
          hideRow: false, // 隐藏选中行和显示选中行
          hideColumn: false, // 隐藏选中列和显示选中列
          clear: false, // 清除内容
          matrix: false, // 矩阵操作选区
          sort: false, // 排序选区
          filter: false, // 筛选选区
          chart: false, // 图表生成
          image: false, // 插入图片
          link: false, // 插入链接
          data: false, // 数据验证
          cellFormat: false // 设置单元格格式
        },
        showinfobar: false, // 显示头部返回标题栏
        data: exportJson.sheets, //excel数据
      });

    },
2,luckysheet 本地引入步骤:

(1)gitee上下载项目: Luckysheet: 🚀Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。

  (2) 下载后执行 npm run build 打包,生成的dist文件中找到以下文件(直接把除了index.html,demoData的copy过去),加入vue public文件夹下

免费开源luckysheet+luckyExcel,本地导入文件,渲染excel,公式计算,导出excel,Vue,前端性能优化,vue.js,excel

(3)index.html引入后,直接在vue组件中就可以用luckysheet对象上的属性和方法了;

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>测试</title>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">

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

  </head>
  <body>
    <div id="app"></div>
  </body>

</html>
3,luckysheet 常用API
luckysheet.getAllSheets() //1,获取所有sheet
//2,排除sheet中的空白行,注意第一个单元格为null的情况,根据实际情况调整
let rowCount = sheet.data.filter(t => t[0] !== null).length;  
//3,获取G列数据,获取cellValue用 v ,修改cellValue V 和 m 都要修改(官网有介绍)
let sheetCol_G = sheet.data.slice(6, rowCount).map(row => row[6].v);
//4,获取L列数据
let sheetSpans_L = this.getSpans(sheet,6,11,rowCount - 6);
//获取合并单元格
 getSpans(sheet,r,c,rs){
          let spans = [], merge = sheet.config.merge;
          for ( let i in merge) {
            let _r = i.split('_')[0], _c = i.split('_')[1];
            if (_c == c && _r >= r && _r < r+rs) { 
              spans.push(merge[i]);
            }
          }
          return spans;
        },
//5,合并单元格按照row顺序排序
 sheetSpans_L.sort((a,b)=>{
            return a.r - b.r;
          });
//6,获取L列非合并单元格:
//(1) 先获取所有合并单元格的rowIndex
 getSpansIndex(spans){
          let spansIndexs = [];
          for(let i = 0; i < spans.length; i++){
            let {r,rs} = spans[i];
               for(let j = 0; j < rs; j++){
                 let index = r + j;
                 spansIndexs.push(index)
               }
          }
          return spansIndexs
        },
//(2)再遍历看L列这行的rowIndex是否包含在里面,不在合并行里就是非合并单元格
 getSingleRow(r,rowCount,col,spans){
  let spansIndexs = this.getSpansIndex(spans);
           let singleRows = [];
           for(let i = r; i < r+rowCount; i++){            
                  singleRows.push({
                    r:i,
                    c: col,
                    rs:1,
                    cs:1
                    })                
             }
           }

//7,修改单元格的值
sheet.data[4][14].m = '新数据'; //4:rowIndex,  14:colIndex
sheet.data[4][14].v = '新数据'; 
//8,修改单元格背景色,字体颜色(注意:导出时exceljs只支持argb格式,与luckysheet不兼容,需要转化)
sheet.data[row][col].bg = "yellow"
sheet.data[row][col].fc = "red"

//9,最后执行refresh页面数据才会更新
luckysheet.refresh();

4,导出excel

(1)直接复制该js文件

import Excel from 'exceljs';
import FileSaver from 'file-saver';

let workbook = null;
const exportSheetExcel = function(table, value, index) {
        //创建工作簿,可以为工作簿添加属性
        if(index === 0){
            workbook = new Excel.Workbook();
        }
        if (table.data.length === 0) { return true; }
        const worksheet = workbook.addWorksheet(table.name);
        const merge = (table.config && table.config.merge) || {};
        const borderInfo = (table.config && table.config.borderInfo) || {};
        // 设置单元格合并,设置单元格边框,设置单元格样式,设置值
        setStyleAndValue(table.data, worksheet);
        setMerge(merge, worksheet);
        setBorder(borderInfo, worksheet);
        // 写入 buffer
        if(index == 4){
            const buffer = workbook.xlsx.writeBuffer().then(data => {
                    const blob = new Blob([data], {
                        type: 'application/vnd.ms-excel;charset=utf-8'
                    });
                    console.log('导出成功!');
                    FileSaver.saveAs(blob, `${value}.xlsx`);
                });
                return buffer;
        }
};

var setMerge = function(luckyMerge = {}, worksheet) {
    const mergearr = Object.values(luckyMerge);
    mergearr.forEach(function(elem) {
    // elem格式:{r: 0, c: 0, rs: 1, cs: 2}
    // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)
        worksheet.mergeCells(
            elem.r + 1,
            elem.c + 1,
            elem.r + elem.rs,
            elem.c + elem.cs
        );
    });
};

var setBorder = function(luckyBorderInfo, worksheet) {
    if (!Array.isArray(luckyBorderInfo)) { return; }
    // console.log('luckyBorderInfo', luckyBorderInfo)
    luckyBorderInfo.forEach(function(elem) {
    // 现在只兼容到borderType 为range的情况
    // console.log('ele', elem)
        if (elem.rangeType === 'range') {
            let border = borderConvert(elem.borderType, elem.style, elem.color);
            let rang = elem.range[0];
            // console.log('range', rang)
            let row = rang.row;
            let column = rang.column;
            for (let i = row[0] + 1; i < row[1] + 2; i++) {
                for (let y = column[0] + 1; y < column[1] + 2; y++) {
                    worksheet.getCell(i, y).border = border;
                }
            }
        }
        if (elem.rangeType === 'cell') {
            // col_index: 2
            // row_index: 1
            // b: {
            //   color: '#d0d4e3'
            //   style: 1
            // }
            const { col_index, row_index } = elem.value;
            const borderData = Object.assign({}, elem.value);
            delete borderData.col_index;
            delete borderData.row_index;
            let border = addborderToCell(borderData, row_index, col_index);
            // console.log('bordre', border, borderData)
            worksheet.getCell(row_index + 1, col_index + 1).border = border;
        }
    // console.log(rang.column_focus + 1, rang.row_focus + 1)
    // worksheet.getCell(rang.row_focus + 1, rang.column_focus + 1).border = border
    });
};
var setStyleAndValue = function(cellArr, worksheet) {
    if (!Array.isArray(cellArr)) { return; }
        cellArr.forEach(function(row, rowid) {
        // const dbrow = worksheet.getRow(rowid+1);
        // //设置单元格行高,默认乘以1.2倍
        // dbrow.height=luckysheet.getRowHeight([rowid])[rowid]*1.2;
        row.every(function(cell, columnid) {
            if(rowid==0){
                const dobCol = worksheet.getColumn(columnid+1);
                //设置单元格列宽除以8
                dobCol.width=luckysheet.getColumnWidth([columnid])[columnid]/8;
            }
            if (!cell) { return true; }
            //设置背景色
            let bg = cell.bg || "#FFFFFF"; //默认white
            bg = bg === 'yellow' ? "FFFF00" : bg.replace('#', '');
            let fill = {
                        type: 'pattern',
                        pattern: 'solid',
                        fgColor: { argb: bg } 
                    };
            let font = fontConvert(
                cell.ff,
                cell.fc,
                cell.bl,
                cell.it,
                cell.fs,
                cell.cl,
                cell.ul
            );
            let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr);
            let value = '';

            if (cell.f) {
                value = { formula: cell.f, result: cell.v };
            } else if (!cell.v && cell.ct && cell.ct.s) {
                // xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后
                // value = cell.ct.s[0].v
                cell.ct.s.forEach(arr => {
                    value += arr.v;
                });
            } else {
                value = cell.v;
            }
            //  style 填入到_value中可以实现填充色
            let letter = createCellPos(columnid);
            let target = worksheet.getCell(letter + (rowid + 1));
            // console.log('1233', letter + (rowid + 1))
            for (const key in fill) {
                target.fill = fill;
                break;
            }
            target.font = font;
            target.alignment = alignment;
            target.value = value;

            return true;
        });
    });
};

var fontConvert = function(
    ff = 0,
    fc = '#000000',
    bl = 0,
    it = 0,
    fs = 10,
    cl = 0,
    ul = 0
) {
    // luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
    const luckyToExcel = {
        0: '微软雅黑',
        1: '宋体(Song)',
        2: '黑体(ST Heiti)',
        3: '楷体(ST Kaiti)',
        4: '仿宋(ST FangSong)',
        5: '新宋体(ST Song)',
        6: '华文新魏',
        7: '华文行楷',
        8: '华文隶书',
        9: 'Arial',
        10: 'Times New Roman ',
        11: 'Tahoma ',
        12: 'Verdana',
        num2bl: function(num) {
            return num === 0 ? false : true;
        }
    };
    // 出现Bug,导入的时候ff为luckyToExcel的val
    
    //设置字体颜色
    fc = fc === 'red' ? 'FFFF0000' : fc.replace('#', '');
    let font = {
        name: typeof ff === 'number' ? luckyToExcel[ff] : ff,
        family: 1,
        size: fs,
        color: { argb: fc },
        bold: luckyToExcel.num2bl(bl),
        italic: luckyToExcel.num2bl(it),
        underline: luckyToExcel.num2bl(ul),
        strike: luckyToExcel.num2bl(cl)
    };

    return font;
};

var alignmentConvert = function(
    vt = 'default',
    ht = 'default',
    tb = 'default',
    tr = 'default'
) {
    // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
    const luckyToExcel = {
        vertical: {
            0: 'middle',
            1: 'top',
            2: 'bottom',
            default: 'top'
        },
        horizontal: {
            0: 'center',
            1: 'left',
            2: 'right',
            default: 'left'
        },
        wrapText: {
            0: false,
            1: false,
            2: true,
            default: false
        },
        textRotation: {
            0: 0,
            1: 45,
            2: -45,
            3: 'vertical',
            4: 90,
            5: -90,
            default: 0
        }
    };

    let alignment = {
        vertical: luckyToExcel.vertical[vt],
        horizontal: luckyToExcel.horizontal[ht],
        wrapText: luckyToExcel.wrapText[tb],
        textRotation: luckyToExcel.textRotation[tr]
    };
    return alignment;
};

var borderConvert = function(borderType, style = 1, color = '#000') {
    // 对应luckysheet的config中borderinfo的的参数
    if (!borderType) {
        return {};
    }
    const luckyToExcel = {
        type: {
            'border-all': 'all',
            'border-top': 'top',
            'border-right': 'right',
            'border-bottom': 'bottom',
            'border-left': 'left'
        },
        style: {
            0: 'none',
            1: 'thin',
            2: 'hair',
            3: 'dotted',
            4: 'dashDot', // 'Dashed',
            5: 'dashDot',
            6: 'dashDotDot',
            7: 'double',
            8: 'medium',
            9: 'mediumDashed',
            10: 'mediumDashDot',
            11: 'mediumDashDotDot',
            12: 'slantDashDot',
            13: 'thick'
        }
    };
    let template = {
        style: luckyToExcel.style[style],
        color: { argb: color.replace('#', '') }
    };
    let border = {};
    if (luckyToExcel.type[borderType] === 'all') {
        border['top'] = template;
        border['right'] = template;
        border['bottom'] = template;
        border['left'] = template;
    } else {
        border[luckyToExcel.type[borderType]] = template;
    }
    // console.log('border', border)
    return border;
};

function addborderToCell(borders, row_index, col_index) {
    let border = {};
    const luckyExcel = {
        type: {
            l: 'left',
            r: 'right',
            b: 'bottom',
            t: 'top'
        },
        style: {
            0: 'none',
            1: 'thin',
            2: 'hair',
            3: 'dotted',
            4: 'dashDot', // 'Dashed',
            5: 'dashDot',
            6: 'dashDotDot',
            7: 'double',
            8: 'medium',
            9: 'mediumDashed',
            10: 'mediumDashDot',
            11: 'mediumDashDotDot',
            12: 'slantDashDot',
            13: 'thick'
        }
    };
    // console.log('borders', borders)
    for (const bor in borders) {
    // console.log(bor)
        if (borders[bor].color.indexOf('rgb') === -1) {
            border[luckyExcel.type[bor]] = {
                style: luckyExcel.style[borders[bor].style],
                color: { argb: borders[bor].color.replace('#', '') }
            };
        } else {
            border[luckyExcel.type[bor]] = {
                style: luckyExcel.style[borders[bor].style],
                color: { argb: borders[bor].color }
            };
        }
    }

    return border;
}

function createCellPos(n) {
    let ordA = 'A'.charCodeAt(0);

    let ordZ = 'Z'.charCodeAt(0);
    let len = ordZ - ordA + 1;
    let s = '';
    while (n >= 0) {
        s = String.fromCharCode((n % len) + ordA) + s;

        n = Math.floor(n / len) - 1;
    }
    return s;
}

export {
    exportSheetExcel
};

(2)使用(用了批量导出优化,显示下载进度),“requestAnimationFrame” 优化由于js计算时造成UI线程阻塞(即页面loading 失效)文章来源地址https://www.toymoban.com/news/detail-741745.html

   handleExport(){
      this.spinning = true;
      const total = 6; //sheet总数+1
      const batchSize = 1; // 每批计算数量
      let current = 0; // 当前计算进度
      let tableArr = luckysheet.getAllSheets();
      const fileName = '测试表_输出';
      const doBatchExport = () => {
        for (let i = 0; i < batchSize; i++) {
          if(current > 0 ){
            let index = current - 1;
            let sheet = tableArr[index];
            exportSheetExcel(sheet, fileName,index);
          }
          current++;  
          // 更新计算进度
          this.updateExportProgress(current, total);
          // 计算完成后
          if (current >= total) {
            return;
          }
        }
        // 继续下一批计算任务
        requestAnimationFrame(doBatchExport);
      };
      // 开始第一批计算任务
      requestAnimationFrame(doBatchExport);
    },
    updateExportProgress(current, total, ){
      if(current < total){
          this.spinningTip = `下载进度( ${(current/(total - 1))*100} % )...`
        }else{
          this.spinning = false;      
        }
    },

到了这里,关于免费开源luckysheet+luckyExcel,本地导入文件,渲染excel,公式计算,导出excel的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【开源组件】- 表格处理 - Luckysheet

    😄生命不息,写作不止 🔥 继续踏上学习之路,学之分享笔记 👊 总有一天我也能像各位大佬一样 🏆 一个有梦有戏的人 @怒放吧德德 🌝分享学习心得,欢迎指正,大家一起学习成长! Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。 官网:h

    2024年02月07日
    浏览(50)
  • 本地文本内容搜索软件(开源免费)

    软件名:本地文本搜索定位器(简称:文本搜索定位器) 今天自荐的是一款关于电脑本地磁盘(NAS映射磁盘也可以)的文件搜索工具(支持文档内容搜索)。 因为个人使用需求,也找了很多相关的软件。但是都或多或少的不能满足我的需求(不一定是软件问题,可能是我的

    2023年04月08日
    浏览(51)
  • 基于Luckysheet实现的协同编辑在线表格支持在线导入数据库,前端导出,前端导入,后端导出

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 这两年,在线表格协作工具越来越火,但开源界一直没有相关的实现,被垄断在几个大厂手上,随着Luckysheet 的横空出世,开源界终于也有一个漂亮能打的在

    2024年02月11日
    浏览(58)
  • 工具.国内开源电子表格-Luckysheet(在线excel)

    国内开源电子表格-Luckysheet(在线excel,功能强大) – 【剪辑之家】 1、背景 现在web技术蓬勃发展,办公应用特别是excel都搬到了线上,比较流行的有腾讯文档,金山文档,石墨文档,google doc,这些都属于企业服务。但是小型企业或者团队,如果想自己搭建一套在线表格系统呢

    2024年02月06日
    浏览(40)
  • Linux 本地文件导入(上传)操作

    一、首先将用 PSFTP 文件从本地服务器传入Linux服务器 1.open : linux 服务器地址 2.login as: 用户名 3.password:密码 4. lcd  本地文件所在路径 5.put -r 文件名  二、 常用 linux 操作命令 1. ll   显示当前目录下所有文件信息 2. cd  /home    到指定目录 3. mv  指定目录 文件 指定目录   ,

    2024年02月06日
    浏览(39)
  • 本地免费GPT4?Llama 2开源大模型,一键部署且无需硬件要求教程

            目前扎克布格带来了最新的Llama 2开源NLP大模型,目前有三个版本分别是70亿参数量,130亿参数量和700亿参数量,庞大的数据集和参数量保证了模型的强大,官网宣称性能与gpt4相比不落下风,又因为开源使得我们可以实现本地化gpt4的梦想并且免费!我们可以通过微

    2024年02月11日
    浏览(63)
  • 本地化部署离线开源免费语音识别API,支持多模态AI能力引擎

    思通数科作为一家专注于多模态AI能力开源引擎平台,其技术产品涵盖了自然语言处理、情感分析、实体识别、图像识别与分类、OCR识别以及语音识别等多个领域。在语音识别这一细分市场,思通数科的技术产品中的音频文件转写服务有着相似的应用场景和功能特点。 思通数

    2024年04月12日
    浏览(64)
  • huggingface transformers loadset 导入本地文件

    点击查看 Huggingface详细入门介绍之dataset库 json : 表示导入的本地文件是 json文件

    2024年02月11日
    浏览(44)
  • 【开源EZRclone】替代RaiDrive,无任何限制免费挂载你的网络存储到本地驱动器

    EZRclone是一个基于PyQt的rclone管理UI界面,初衷是让rclone更好用,一定程度上替代raidrive等收费软件。 github链接:https://github.com/0oljyo0/EZRclone(可能无法实时更新,gitee为最新版本。) gitee链接:https://gitee.com/o0ljy0o/ezrclone 开机自启动并最小化到系统托盘 配置挂载本地驱动器 启动后自

    2024年02月01日
    浏览(81)
  • git 怎么导入本地仓库-将本地文件夹添加到Git仓库

    1、(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库 2、把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点“.”,意为添加文件夹下的所有文件 3、用命令 git commit告诉Git,把文件提交到仓库。引号内为提交说明 4、关

    2023年04月11日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包