DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>
#luckysheet {
width: 100%;
height: 600px;
}
style>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js">script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js">script>
head>
<body>
<div id="luckysheet">div>
body>
<script>
luckysheet.create()
script>
luckysheet.create({
container: 'luckysheet', // luckysheet为容器id
lang: 'zh', // 设定表格语言
data: [
{
name: '工作表名称',
row: 30, // 行数
column: 30, // 列数
// defaultRowHeight: 19, // 自定义行高
// defaultColWidth: 73, // 自定义列宽
// 初始化使用的单元格数据
celldata: [
{
r: '0',
c: '1',
v: {
m: 'img \r\n 555 123',
v: 'img \r\n 555 123',
fc: '#ff0000',
tb: 2, // 内容超出自动换行
}
},
{
r: '0',
c: '3',
v: {
m: 'rq',
v: 'rq',
}
},
{
r: '0',
c: '5',
v: {
m: 'rq',
v: 'rq',
}
},
{
r: '3',
c: '5',
v: {
m: 'img',
v: 'img',
}
}
]
}
],
});
function search() {
console.log(luckysheet.find("rq")); // 返回数组
}
// 设置所有单元格自动换行
// 需要先设置换行,再写入值,才有效果。先设置值,再设置换行,没有效果
function setTextWrap() {
const rowNum = allSheetData.length; // 表格行数
const colNum = allSheetData[0].length; // 表格列数
for (let _row = 0; _row < rowNum; _row++) {
for (let _col = 0; _col < colNum; _col++) {
luckysheet.setCellValue(_row, _col, {
tb: 2,
// bg: "#FF0000"
}, {
// 是否刷新界面,默认true,多单元格赋值时控制节流,前面单元格置为false,最后一个单一个置为true
isRefresh: _row === rowNum - 1 && _col === colNum - 1,
success: () => {}
})
}
}
}
// 替换格子内容
function replace() {
range = luckysheet.getRange(); // 存放原来的选中区域
luckysheet.find("rq").forEach(({ row, column }, index, arr) => {
luckysheet.setCellValue(row, column, {
m: '2020- \r\n 星期日',
v: '2020- \r\n 星期日',
tb: 2,
isRefresh: true, // 是否刷新界面,默认true,多单元格赋值时控制节流,前面单元格置为false,最后一个单一个置为true
}, {
success: () => {
// 先选中
luckysheet.setRangeShow({ row:[row], column:[column] });
// 再进入编辑模式,让换行生效
luckysheet.enterEditMode({
success: () => {
if (index === arr.length - 1) {
// 退出编辑模式
luckysheet.exitEditMode();
// 选中替换前的选区
luckysheet.setRangeShow({ row: range[0].row, column: range[0].column })
}
}
});
}
});
})
}
function insertImage() {
/** @desc mc是合并单元格后的数据 */
luckysheet.find("img").forEach(({ row, column, mc }) => {
const cellWidth = luckysheet.getColumnWidth([column])[column];
const cellHeight = luckysheet.getRowHeight([row])[row];
let img = new Image();
img.src = './demo.jpg';
img.width = cellWidth * (mc?.cs || 1);
img.height = cellHeight * (mc?.rs || 1);
img.onload = function () {
let canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
const context = canvas.getContext('2d');
context.drawImage(img, 0, 0, this.width, this.height);
const dataUrl = canvas.toDataURL("image/png");
luckysheet.clearCell(row, column);
luckysheet.insertImage(dataUrl, {
order: 0,
rowIndex: row,
colIndex: column,
success: () => {
// 【源代码】src/controllers/imageCtrl.js:677 fixme 插入图片 宽/高内部设置为400
}
});
}
})
}
源代码中,插入图片时,图片的默认展示尺寸为宽/高400,需要点击图片,选择恢复原图,才是图片的真实宽高。
我的需求时,插入的图片根据格子的大小,自动填满整个格子。所以我把src/controllers/imageCtrl.js:677
的代码改了,打包后,项目引用本地文件
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
<script src="plugin.js">script>
<script src="luckysheet.umd.js">script>
function getConfig() {
console.log(luckysheet.getAllSheets());
}
初始化数据或者用方法修改内容,内容中含有换行符,页面的格子没有换行,需要双击格子,进入编辑模式,换行才会生效。
我的解决方法:表格创建后,查找含有换行符的格子,逐个进入编辑模式,然后退出编辑模式
luckysheet.create({
container: 'luckysheet', // luckysheet为容器id
lang: 'zh', // 设定表格语言
data: [
{
name: '工作表名称',
row: 30, // 行数
column: 30, // 列数
// defaultRowHeight: 19, // 自定义行高
// defaultColWidth: 73, // 自定义列宽
// 初始化使用的单元格数据
celldata: [
{
r: '0',
c: '1',
v: {
m: 'img \r\n 555 123',
v: 'img \r\n 555 123',
fc: '#ff0000',
tb: 2, // 内容超出自动换行
}
},
{
r: '0',
c: '3',
v: {
m: 'rq',
v: 'rq',
}
},
{
r: '0',
c: '5',
v: {
m: 'rq',
v: 'rq',
}
},
{
r: '3',
c: '5',
v: {
m: 'img',
v: 'img',
}
}
]
}
],
hook: {
// 表格创建之后触发
workbookCreateAfter:function(allConfig){
console.log(allConfig);
luckysheet.find("\n").forEach(({ row, column }, index, arr) => {
luckysheet.setRangeShow({ row:[row], column:[column] }, {
success: () => {
// 进入编辑模式,让换行生效
luckysheet.enterEditMode({
success: () => {
if (index === arr.length - 1) {
// 退出编辑模式
luckysheet.exitEditMode();
// 选中第一个格子
luckysheet.setRangeShow({ row:[0], column:[0] }, {
show: false, // 选中状态不要高亮
})
}
}
});
}
})
});
allSheetData = luckysheet.getSheetData();
}
}
});
// 写入表格数据
setData () {
const { excelData } = this;
let setCount = 0;
Object.keys(excelData).forEach((key) => {
luckysheet.find(key, {
type: 'v', // 查找原始值,替换显示值,后期可以重复更新
// isWholeWord: true, // 整词匹配,避免匹配到其它的格子 有合并格子会报错
})
.filter(fItem => fItem.v === key) // 因为整词匹配遇到合并格子会报错,所以在结果里过滤原始值全等的项
.forEach(({ row, column }) => {
setCount += 1
if (excelData[key].startsWith('http')) {
const img = new Image()
img.setAttribute('crossOrigin', 'anonymous')
img.src = excelData[key]
img.width = '200'
img.height = '200'
img.onload = () => {
let canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
const context = canvas.getContext('2d')
context.drawImage(img, 0, 0, img.width, img.height)
const quality = 0.8
const dataUrl = canvas.toDataURL('image/png', quality)
luckysheet.setCellValue(row, column, { m: '' }, {
success: () => {
luckysheet.insertImage(dataUrl, {
rowIndex: row,
colIndex: column,
success: () => {
setCount--
this.getShot(setCount)
}
})
}
});
}
return
}
luckysheet.setCellValue(row, column, {
m: excelData[key], // 设置显示值
v: excelData[key], // 设置显示值
// 设置为纯文本模式,避免设置日期 e.g. 2020-08-29时,编辑模式弹出个日期选择器
ct: {
fa: "@",
t: "s"
},
// tb: 2, // 文本超出格子,自动换行。自动编辑模式撑开高度时,高度会变得很高
ht: 1, // 文字左对齐
}, {
success: () => {
// 先选中
luckysheet.setRangeShow({ row:[row], column:[column] });
// 再进入编辑模式,让换行生效,默认值v才能撑开格子
luckysheet.enterEditMode({
success: () => {
// 退出编辑模式
luckysheet.exitEditMode();
setCount--
this.getShot(setCount)
}
});
}
})
})
})
},
/**
* 获取表格图片
* @params setCount 正在进行赋值操作的格子数
* */
getShot(setCount) {
if (setCount > 0) {
return;
}
const sheetData = luckysheet.getSheetData();
luckysheet.setRangeShow({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] }, {
success: () => {
const shot = luckysheet.getScreenshot({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] });
this.url = shot
}
}
)
},
要选中表格区域,才能截图
正常情况,截图里没有出现你插入的图片
const sheetData = luckysheet.getSheetData();
luckysheet.setRangeShow({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] }, {
success: () => {
const shot = luckysheet.getScreenshot({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] });
this.url = shot
}
}
)
先把能截出来的底图画在canvas上,然后遍历图片信息,再上一步的基础上把图片加上去
我遇到的问题是,图片位置不能对在格子上,会出现偏移,无解
// 表格截图
// 获取表格图片
function getShot() {
luckysheet.setRangeShow({ row: [0, allSheetData.length - 1], column: [0, allSheetData[0].length - 1] }, {
success: () => {
const shot = luckysheet.getScreenshot({ row: [0, allSheetData.length - 1], column: [0, allSheetData[0].length - 1] });
let { ch_width, rh_height, images = {} } = luckysheet.getAllSheets()[0];
if (Object.keys(images).length) {
let canvas = document.createElement('canvas');
canvas.width = ch_width;
canvas.height = rh_height;
const context = canvas.getContext('2d');
const img = new Image();
img.src = shot;
img.width = ch_width;
img.height = rh_height;
img.onload = function () {
context.drawImage(img, 0, 0, this.width, this.height);
const dataUrl = canvas.toDataURL("image/png");
Object.values(images).forEach((image, index, arr) => {
const img = new Image();
img.src = image.src;
img.width = image.originWidth;
img.height = image.originHeight;
img.onload = function () {
context.drawImage(img, image.default.left, image.default.top, this.width, this.height);
if (index === arr.length - 1) {
const dataUrl = canvas.toDataURL("image/png");
}
}
})
};
}
}
}
)
}
import printJS from "print-js";
// 打印
handlePrint() {
if (!this.url) {
console.error('没有图片');
return;
}
printJS(
{
printable: this.url,
type: 'image',
documentTitle: '表格名称',
style: '@page{size:auto;margin: 0cm 1cm 0cm 1cm;}' // 去除页眉页脚
}
)
},
// 加载表格
loadSheet() {
luckysheet.create({
...this.sheetOptions, // 后端返回的一些通用配置、格子数据
showtoolbarConfig: {},
enableAddRow: false,
enableAddBackTop: false,
})
// 获取表格数据,然后通过上面表格初始化填上的key,进行替换操作
this.getExcelData();
},
主要是对上面截图的导出
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas'
// 导出表格数据
async exportTableData() {
this.$message('导出中...');
setTimeout(() => {
const element = document.querySelector(".el-image > img");
// window.pageYOffset = 0;
// document.documentElement.scrollTop = 0
// document.body.scrollTop = 0
html2canvas(element,{
// height: node.offsetHeight,
allowTaint: true,
// allowTaint: true,
logging:true,
scale: 2 // 提升画面质量,但是会增加文件大小
}).then(function (canvas) {
var contentWidth = canvas.width;
var contentHeight = canvas.height;
//一页pdf显示html页面生成的canvas高度;
var pageHeight = contentWidth / 592.28 * 841.89;
//未生成pdf的html页面高度
var leftHeight = contentHeight;
//页面偏移
var position = 0;
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
var imgWidth = 595.28;
var imgHeight = 592.28 / contentWidth * contentHeight;
var pageData = canvas.toDataURL('image/jpeg', 1.0);
var pdf = new jsPDF('', 'pt', 'a4');
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
} else { // 分页
while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight;
position -= 841.89;
//避免添加空白页
if (leftHeight > 0) {
pdf.addPage();
}
}
}
pdf.setFont('simsun');
pdf.save('记录.pdf');
});
}, 1000)
},
需要把结构渲染出来,然后设置为不可见,不然我手动触发格子的编辑模式来撑开格子位置就不能生效
<div class="imgBox" v-else v-show="true">
<el-image
:src="url"
:preview-src-list="[url]"
/>
div>
<div class="sheet-container" style="z-index: -1">
<div class="print_content" id="luckysheet" />
div>
.sheet-container {
width: 100%;
height: 500px;
position: relative;
.print_content {
width: 100%;
height: 100%;
}
}
.imgBox {
height: calc(100% - 80px);
overflow: auto;
}
【github】
表格已经设置了行高,进入编辑模式,让换行生效后退出,格子高度会变高
originSheetOptions: {}, // 表格信息和配置,存储第一次的配置,不会改变
sheetOptions: {}, // 表格信息和配置,操作表格,里面的数据会变
// opt是后台接口返回的表格数据和配置
// 换行后格子高度会变化,数据也会被修改,所以要把原始的配置存起来,用来做修复
// cloneDeep是深拷贝,避免数据污染
this.originSheetOptions = cloneDeep(opt);
this.sheetOptions = cloneDeep(opt);
// 加载表格
loadSheet() {
luckysheet.create({
...this.sheetOptions,
// showtoolbarConfig: {},
// enableAddRow: false,
// enableAddBackTop: false,
})
// 获取真实数据,替换表格的占位内容
this.getExcelData();
}
// 一系列操作,如,替换占位内容,插入图片等
// 重新设置行高,修复格子高度变高的问题
fixRowHeight() {
const rowHeight = this.originSheetOptions.data[0].config.rowlen;
return new Promise(resolve => {
luckysheet.setRowHeight(rowHeight, {
success: () => {
resolve()
}
});
})
},
文字样式如:字体大小,字体颜色等
const findItems = luckysheet.find(key, {
type: 'v', // 查找原始值,替换显示值,后期可以重复更新
// isWholeWord: true, // 整词匹配,避免匹配到其它的格子 有合并格子会报错
}).filter(fItem => fItem.v === key); // 因为整词匹配遇到合并格子会报错,所以在结果里过滤原始值全等的项
findItems.forEach(({ row, column, ...args }, cellIndex, cellArr) => {}
luckysheet.setCellValue(row, column, {
m: excelData[key], // 设置显示值
v: excelData[key], // 设置原始值
}, {
success: () => {
// 先选中
luckysheet.setRangeShow({ row:[row], column:[column] });
// 再进入编辑模式,让换行生效,默认值v才能撑开格子
luckysheet.enterEditMode({
success: () => {
// 退出编辑模式
luckysheet.exitEditMode({
success: () => {
// 当setCellValue的值存在换行符,同时用编辑模式来让换行生效后,所在格子的v、m属性会被删除,后续无法通过luckysheet.find找到格子
// v的值会被移动到 格子.ct.s[0].v 里面
// 和文字相关的属性如ff(字体),还在原来的位置,如格子.ff,造成文字相关的样式丢失,所以需要把格子.文字相关样式 移动到 格子.ct.s[0]里面
const rangeValue = luckysheet.getRangeValuesWithFlatte();
if (rangeValue[0].ct.s) {
const { ff, fs, fc, bl, it, cl, un } = args;
rangeValue[0].ct.s[0] = {
...rangeValue[0].ct.s[0],
ff, // 字体
fs, // 字体大小
fc, // 字体颜色
bl, // 粗体
it, // 斜体
cl, // 删除线
un, // 下划线
}
}
...
}
});
}
});
}
})
// 修改表格配置
opt.devicePixelRatio = 4; // 避免导出图片模糊
// 修改表格配置
opt.zoomRatio = 1; // 避免插入图片偏移
出现的原因是
保存配置时,表格是缩放到80%的
重新加载表格时,表格读取配置,显示为80%
这时往指定单元格插入图片时,就会出现偏移
需要在加载表格前,把缩放比例配置设为100%,再进行插入