Luckysheet 介绍
Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。
实现功能
格式设置
样式 (修改字体样式,字号,颜色或者其他通用的样式)条件格式 (突出显示所关注的单元格或单元格区域;强调异常值;使用数据栏、色阶和图标集(与数据中的特定变体对应)直观地显示数据)文本对齐及旋转支持文本的截断、溢出、自动换行数据类型 货币, 百分比, 数字, 日期Custom (和excel保持一致,例如:##,###0.00
, $1,234.56$##,###0.00_);[Red]($##,###0.00)
, _($* ##,###0.00_);_(...($* "-"_);_(@_)
, 08-05 PM 01:30MM-dd AM/PM hh:mm
) 单元格内多样式 (Alt+Enter单元格内换行、上标、下标、单元格内可定义每个文字的不同样式) 单元格
拖拽选取来修改单元格 (对选区进行操作,可以拖动四边来移动选区,也可以在右下角对选区进行下拉填充操作)选区下拉填充 (对于一个1,2,3,4,5的序列,将会按照间隔为1进行下拉填充,而对2,4,6,8将会以2作为间隔。支持等差数列,等比数列,日期,周,天,月,年,中文数字填充)自动填充选项 (下拉填充后,会出现填充选项的菜单,支持选择复制,序列,仅格式,只填充格式,天,月,年的选择)多选区操作 (可以按住Ctrl键进行单元格多选操作,支持多选区的复制粘贴)查找和替换 (对内容进行查找替换,支持正则表达式,整词,大小写敏感)定位 (可以根据单元格的数据类型进行自动定位并选中,选中后可以批量进行格式等操作)合并单元格数据验证(表单功能) (支持Checkbox, drop-down list, datePicker)行和列操作
隐藏,插入,删除行或列冻结行或列 (支持冻结首行和首列,冻结到选区,冻结调节杆可以进行拖动操作)文本分列 (可以把文本根据不同符号进行拆分,和excel的分列功能类似)操作体验
撤销/恢复
复制/粘贴/剪切操作 (支持Luckysheet到excel和excel到Luckysheet带格式的互相拷贝)
快捷键支持 (快捷键操作保持与excel一致)
快捷键 | 功能 |
---|---|
CTRL + C | 复制单元格 |
CTRL + V | 粘贴单元格 |
CTRL + X | 剪切单元格 |
CTRL + Z | 撤销 |
CTRL + Y | 重做 |
CTRL + A | 全选 |
CTRL + B | 加粗 |
CTRL + F | 查找 |
CTRL + H | 替换 |
CTRL + I | 斜体 |
CTRL + UP/DOWN/LEFT/RIGHT | 快捷调整单元格选框 |
SHIFT + UP/DOWN/LEFT/RIGHT | 调整选区 |
CTRL + 鼠标左击 | 多选单元格 |
SHIFT + 鼠标左击 | 调整选区 |
UP/DOWN/LEFT/RIGHT | 移动单元格选框 |
ENTER | 编辑单元格 |
TAB | 向右移动单元格选框 |
DELETE | 清除单元格数据 |
格式刷 (与google sheet类似)
任意选区拖拽 (选择单元格,输入公式,插入图表,会与选区相关,可以通过任意拖动和放大缩小选区来改变与之关联的参数)
公式和函数
内置公式 数学 (SUMIFS, AVERAGEIFS, SUMIF, SUM, etc.)文本 (CONCATENATE, REGEXMATCH, MID)日期 (DATEVALUE, DATEDIF, NOW, WEEKDAY, etc.)财务 (PV, FV, IRR, NPV, etc.)逻辑 (IF, AND, OR, IFERROR, etc.)查找和引用 (VLOOKUP, HLOOkUP, INDIRECT, OFFSET, etc.)动态数组 (Excel2019新函数,SORT,FILTER,UNIQUE,RANDARRAY,SEQUENCE) 公式支持数组 (={1,2,3,4,5,6}, Crtl+Shift+Enter)远程公式 (DM_TEXT_TFIDF, DM_TEXT_TEXTRANK,DATA_CN_STOCK_CLOSE etc. Need remote interface, can realize complex calculation)自定义公式 (根据身份证识别年龄,性别,生日,省份,城市等. AGE_BY_IDCARD, SEX_BY_IDCARD, BIRTHDAY_BY_IDCARD, PROVINCE_BY_IDCARD, CITY_BY_IDCARD, etc. 可以任意加入自己的公式哦)表格操作
筛选 (支持颜色、数字、字符、日期的筛选)排序 (同时加入多个字段进行排序)数据透视表
字段拖拽 (操作方式与excel类似,拖动字段到行、列、数值、筛选等4个区域)聚合方式 (支持汇总、计数、去重计数、平均、最大、最小、中位数、协方差、标准差、方差等计算)筛选数据 (可对字段进行筛选后再进行汇总)数据透视表下钻 (双击数据透视表中的数据,可以下钻查看到明细,操作方式与excel一致)根据数据透视表新建图表 (数据透视表产生的数据也可以进行图表的制作)图表
支持的图表类型 (目前折线图、柱状图、面积图、条形图、饼图可以使用,散点图、雷达图、仪表盘、漏斗图正在接入,其他图表正在陆续开发中,请大家给予建议)关于图表插件 (图表使用了一个中间插件ChartMix (opens new window)(MIT协议): 目前支持ECharts,正在逐步接入Highcharts、阿里G2、amCharts、googleChart、chart.js)Sparklines小图 (以公式的形式进行设置和展示,目前支持:折线图、面积图、柱状图、累积图、条形图、离散图、三态图、饼图、箱线图等)插入对象
插入图片 (支持JPG,PNG,SVG的插入、修改和删除,并且随表格的变动而产生变化)Luckysheet专有
矩阵计算 (通过右键菜单进行支持:对选区内的数据进行转置、旋转、数值计算)截图 (把选区的内容进行截图展示)复制到其他格式 (右键菜单的"复制为", 支持复制为json、array、对角线数据、去重等)功能界面
功能界面如下:
在vue中引入Luckysheet
Luckysheet文档
Luckysheet社区
Luckysheet github地址
LuckySheet打包
克隆源码
克隆Luckysheet源码到本地
git clone https://github.com/dream-num/Luckysheet.git
安装依赖
npm installnpm install gulp -g
开发
npm run dev
打包
npm run build
Luckysheet 使用步骤
1.本地引入
npm run build
后 dist
文件夹下的所有文件复制到vue项目的public目录下,然后在index.html文件中通过相对路径引入:
<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>
2.指定一个表格容器
<div id="luckysheet" class="luckysheet-wrap"></div><style scoped>.luckysheet-wrap { margin: 0px; padding: 0px; position: absolute; width: 100%; height: 100%; left: 0px; top: 0px;}</style>
3.创建一个表格
data () { return { // 配置项 options: { container: 'luckysheet', // DOM容器的ID title: '电子表格', // 工作簿名称 lang: 'zh', // 设定表格的语言 showtoolbarConfig: { print: false, // 工具栏隐藏打印按钮 }, showsheetbarConfig: { add: false, // 底部sheet页隐藏新增sheet按钮 menu: false, // 底部sheet页隐藏管理按钮 }, sheetRightClickConfig: { hide: false, // 隐藏,取消隐藏 move: false, // 向左移,向右移 } } }; },mounted () { this.createSheet()},methods:{ // 创建工作表 createSheet () { // 初始化表格 luckysheet.create(this.options) // 获取Luckysheet表格文件的数据 this.sheetfile = luckysheet.getluckysheetfile() // console.log(this.sheetfile) }}
Luckysheet 整体配置
基础结构
初始化表格时,可以设置一个对象 options
来自定义配置Luckysheet表格。
如下是一个简洁的配置案例:
// 配置项const options = { container: 'luckysheet', // 设定DOM容器的id title: 'Luckysheet Demo', // 设定表格名称 lang: 'zh' // 设定表格语言 // 更多其他设置...}// 初始化表格luckysheet.create(options)
这里的 options
配置项会作用于整个表格,单个sheet的配置则需要在 options.data
数组中,分别设置对应更详细的参数,参考工作表配置
常用配置
container
类型:String默认值:“luckysheet”作用:容器的IDtitle
类型:String默认值:“Luckysheet Demo”作用:工作簿名称lang
类型:String默认值:“en”作用:国际化设置,允许设置表格的语言,支持简体中文(“zh”)、英文(“en”)、繁体中文(“zh_tw”)和西班牙文(“es”)data
类型:Array默认值:[{ “name”: “Sheet1”, color: “”, “status”: “1”, “order”: “0”, “data”: [], “config”: {}, “index”:0 }, { “name”: “Sheet2”, color: “”, “status”: “0”, “order”: “1”, “data”: [], “config”: {}, “index”:1 }, { “name”: “Sheet3”, color: “”, “status”: “0”, “order”: “2”, “data”: [], “config”: {}, “index”:2 }]作用:当未配置loadUrl
和loadSheetUrl
的时候,需要手动配置传入整个客户端所有sheet数据[shee1, sheet2, sheet3]
,详细参数设置参见工作表配置 plugins
类型:Array默认值:[]作用:配置插件,支持图表:“chart”column
类型:Number默认值:60作用:空表格默认的列数量row
类型:Number默认值:84作用:空表格默认的行数据量showtoolbar
类型:Boolean默认值:true作用:是否显示工具栏showtoolbarConfig
类型:Object
默认值:{}
作用:自定义配置工具栏,可以与showtoolbar配合使用,showtoolbarConfig
拥有更高的优先级。
示例:
仅显示撤消重做和字体按钮:
// options{ showtoolbar: false, showtoolbarConfig:{ undoRedo: true, font: true, }}
仅隐藏图片和打印按钮:
// options{showtoolbar: true, // 默认就是true,可以不设置showtoolbarConfig:{image: false,print: false,}}
showsheetbar
类型:Boolean默认值:true作用:是否显示底部sheet页按钮showsheetbarConfig
类型:Object
默认值:{}
作用:自定义配置底部sheet页按钮,可以与showsheetbar配合使用,showsheetbarConfig
拥有更高的优先级。
格式:
{ add: false, // 新增sheet menu: false, // sheet管理菜单 sheet: false // sheet页显示}
示例:
仅显示新增sheet按钮:
// options{ showsheetbar: false, showsheetbarConfig:{ add: true,}}
仅隐藏新增sheet和管理按钮:
// options{ showsheetbar: true, // 默认就是true,可以不设置 showsheetbarConfig:{ add: false, menu: false, }}
sheetRightClickConfig
类型:Object
默认值:{}
作用:自定义配置sheet页右击菜单
格式:
{ delete: false, // 删除 copy: false, // 复制 rename: false, // 重命名 color: false, // 更改颜色 hide: false, // 隐藏,取消隐藏 move: false, // 向左移,向右移}
钩子函数
钩子函数应用于二次开发时,会在各个常用鼠标或者键盘操作时植入钩子,调用开发者传入的函数,起到扩展Luckysheet功能的作用。
钩子函数统一配置在options.hook
下,可以分别针对单元格、sheet页、表格创建配置hook。
使用案例可参考源码 src/index.html
常用钩子函数如下:
鼠标钩子
:
scroll
类型:Function默认值:null作用:鼠标滚动事件参数: {Object} [position]: {Number} [scrollLeft]:横向滚动条的位置{Number} [scrollTop]:垂直滚动条的位置{Number} [canvasHeight]:canvas高度工作簿
:
workbookCreateAfter
类型:Function默认值:null作用:表格创建之后触发参数: {Object} [book]: 整个工作簿的配置(options)Luckysheet 常用 API 操作
单元格操作
getCellValue(row, column [,setting])
参数:
{Number} [row]: 单元格所在行数;从0开始的整数,0表示第一行{Number} [column]: 单元格所在列数;从0开始的整数,0表示第一列{PlainObject} [setting]: 可选参数 {String} [type]: 单元格的值类型,可以设置为原始值v
或者显示值m
;默认值为v
,表示获取单元格的实际值{Number} [order]: 工作表下标;默认值为当前工作表下标 说明:
获取单元格的值。
特殊情况,单元格格式为yyyy-MM-dd
,type
为'v'
时会强制取'm'
显示值
setCellValue(row, column, value [,setting])
参数:
{Number} [row]: 单元格所在行数;从0开始的整数,0表示第一行{Number} [column]: 单元格所在列数;从0开始的整数,0表示第一列{Object | String | Number} [value]: 要设置的值;可以为字符串或数字,或为符合Luckysheet单元格格式的对象{PlainObject} [setting]: 可选参数 {Number} [order]: 工作表下标;默认值为当前工作表下标{Boolean} [isRefresh]: 是否刷新界面;默认为true
;用于多个单元格赋值时候控制节流,前面单元格赋值的时候应设置为 false
,最后一个单元格赋值时设置为true
。{Function} [success]: 操作结束的回调函数 说明:
设置某个单元格的值,也可以设置整个单元格对象,用于同时设置多个单元格属性。
如果需要更新公式,也可以在这里赋值,Luckysheet在内部会主动把这个公式做计算并加入到公式链中,最后重刷界面。
选区操作
getRangeJson(title [,setting])
参数:
{Boolean} [title]: 是否首行为标题
title
可能的值有:
"true"
: 首行为标题"false"
: 首行不为标题 {PlainObject} [setting]: 可选参数
{Array | Object | String} [range]: 选区范围,支持选区的格式为"A1:B2"
、"sheetName!A1:B2"
或者{row:[0,1],column:[0,1]}
,只能为单个选区;默认为当前选区{Number} [order]: 工作表下标;默认值为当前工作表下标 说明:
复制指定工作表指定单元格区域的数据,返回json
格式的数据
工作表操作
getAllSheets()
说明:
返回所有工作表配置,格式同工作表配置,得到的结果可用于表格初始化时作为options.data使用。
所以此API适用于,手动操作配置完一个表格后,将所有工作表信息取出来自行保存,再用于其他地方的表格创建。如果想得到包括工作簿配置在内的所有工作簿数据,推荐使用 toJson,并且可以直接用于初始化Luckysheet。
示例:
取得第一个工作表的所有基本信息luckysheet.getAllSheets()[0]
getLuckysheetfile()
说明:
返回所有表格数据结构的一维数组luckysheetfile
,不同于getAllSheets
方法,此方法得到的工作表参数会包含很多内部使用变量,最明显的区别是表格数据操作会维护luckysheetfile[i].data
,而初始化数据采用的是options.data[i].celldata
,所以luckysheetfile
可用于调试使用,但是不适用初始化表格。
除此之外,加载过的工作表参数中会增加一个load = 1
,这个参数在初始化数据的时候需要置为0才行。所以,将getLuckysheetfile()
得到的数据拿来初始化工作簿,需要做两个工作:
现在已有getAllSheets
来完成这个工作,无需再手动转化数据。
示例:
取得第一个工作表的所有调试信息luckysheet.getLuckysheetfile()[0]
工作簿操作
create(options)
参数:
{Object} [options]:表格的所有配置信息说明:
初始化一个Luckysheet,可包含多个工作表
getWorkbookName([,setting])
参数:
{PlainObject} [setting]: 可选参数 {Function} [success]: 操作结束的回调函数说明:
获取工作簿名称
Luckysheet 自定义操作
导入JSON数据
// 导入json数据importJson (data) { let range = luckysheet.getRange() // console.log(range) let row = range[0].row[0] let column = range[0].column[0] if (data.length > 0) { let keys = Object.keys(data[0]) // console.log(keys) keys.forEach((item, index) => { luckysheet.setCellValue(row, column + index, item) }) } data.forEach((item1, index1) => { // console.log(item1) let values = Object.values(item1) // console.log(values) values.forEach((item2, index2) => { luckysheet.setCellValue(row + 1 + index1, column + index2, item2) }) })}
sheetData是一个JSON数组,格式如下:
[ {"年级":"初一","姓名":"李四","学号":7142,"年龄":18,"籍贯":"河北","成绩":79}, {"年级":"初二","姓名":"王五","学号":7143,"年龄":19,"籍贯":"河北","成绩":80}, {"年级":"初三","姓名":"李华","学号":7144,"年龄":20,"籍贯":"山东","成绩":81}, {"年级":"初一","姓名":"赵国","学号":7145,"年龄":21,"籍贯":"河北","成绩":82}, {"年级":"初一","姓名":"李青","学号":7146,"年龄":22,"籍贯":"河北","成绩":83}, {"年级":"初三","姓名":"王国","学号":7147,"年龄":23,"籍贯":"山西","成绩":84}, {"年级":"初一","姓名":"正东","学号":7148,"年龄":24,"籍贯":"四川","成绩":85}, {"年级":"初二","姓名":"钱多","学号":7149,"年龄":25,"籍贯":"河北","成绩":86}, {"年级":"初一","姓名":"付丽","学号":7150,"年龄":26,"籍贯":"贵州","成绩":87}]
导出JSON数据
选中工作区,才能导出JSON数据
// 导出json数据exportJson () { let jsonData = luckysheet.getRangeJson(true) console.log(jsonData)}
导出csv格式
选中工作区,才能导出csv格式的数据
// 导出工作表csv格式exportCsv () { let name = luckysheet.getWorkbookName() // console.log(name) let exceldata = luckysheet.getRangeJson(true) // console.log(exceldata) let data = "" let keys = Object.keys(exceldata[0]) // console.log(keys) data = keys.join(",") exceldata.forEach(item => { let values = Object.values(item) // console.log(values) data += "\n" + values.join(",") }) // console.log(data) // Download element var blob = new Blob(["\uFEFF" + data], { type: 'text/csv;charset=utf-8;' }); // IE Compatibility if (window.navigator && window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveOrOpenBlob(blob, name + '.csv'); } else { // Download element var pom = document.createElement('a'); var url = URL.createObjectURL(blob); pom.href = url; pom.setAttribute('download', name + '.csv'); document.body.appendChild(pom); pom.click(); pom.parentNode.removeChild(pom); }},
保存数据给后端接口
// 保存工作表数据saveData () { let data = luckysheet.getLuckysheetfile() data.forEach((item, index) => { if (item.chart) { item.chart.forEach((chart, i) => { data[index].chart[i] = { ...data[index].chart[i], chartOptions: { ...chartmix.default.getChartJson(chart.chart_id) } } let div = document.getElementById(chart.chart_id + '_c'); if (div.style) { data[index].chart[i].left = parseInt(div.style.left) data[index].chart[i].top = parseInt(div.style.top) data[index].chart[i].width = parseInt(div.style.width) data[index].chart[i].height = parseInt(div.style.height) } }) } }) console.log(data)}
从后端接口加载数据
创建表格前,手动配置传入整个客户端所有sheet数据的options的data选项
mounted () { this.setData() // this.createSheet() // this.addButton()},methods: { setData () { this.$axios.post("/api/sheetData").then(res => { console.log(res) this.$set(this.options, "data", res.data) // this.options.data = res.data console.log(this.options.data) this.createSheet() }) }}
Luckysheet 性能测试
单条数据量不大的情况下,支持5000+的数据量不卡
Luckysheet 源码项目结构
src/controllers/ sheet 主要操作
conditionformat 条件格式constant.js 页面结构html模板代码controlHistory.js 撤销操作dataVerificationCtrl.js 数据验证操作dropCell.js 选区下拉expendPlugins.js 插件扩展filter.js 筛选排序formulaBar.js 公示栏freezen.js 行列冻结操作hyperlinkCtrl.js 插入链接操作ifFormulaGenerator.js if公式生成器imageCtrl.js 插入图片及图片设置insertFormula.js 插入函数sheetmanage.js sheet操作代码sheetBar.js 表格底部名称栏区域 相关事件(增、删、改、隐藏显示、颜色等等)splitColumn.js 分列操作toolbar.js 工具栏按钮配置src/expendPlugins/ 扩展
chart 图表扩展src/locale/ 语言包
zh.js 中文包src/config.js 默认导出sheet创建配置信息
src/css/luckysheet-core.css 页面结构样式类