本帖最后由 Asher 于 2025-12-29 19:28 编辑
使用https://docs.grapecity.com.cn/spreadjs/practice//cell/customize-cell-html的方式自定义富文本的编辑框,在回显到sheet上时单元格高度未达到预期,paint方法中获取的高度最小都是40,切wordWrap设置true也没有效果
demo代码如下:输入包含html标签的文本,比如<span>eee</span>
<template>
<div>
<div id="ss" style="width: 100%; height: 600px;"></div>
<div v-if="dialogVisible" class="modal-overlay" @click.self="closeModal">
<div class="modal-container">
<div class="modal-header">
<span class="modal-title">富文本编辑框 </span>
<button class="modal-close" @click="closeModal">×</button>
</div>
<div class="modal-body">
<input v-model="richValue" />
</div>
<div class="modal-footer">
<button class="modal-btn" @click="handleSave">确定</button>
<button class="modal-btn modal-btn-cancel" @click="closeModal">取消</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import GC from '@grapecity/spread-sheets';
import '@grapecity/spread-sheets/styles/gc.spread.sheets.excel2016colorful.css';
import '@grapecity/spread-sheets-designer/styles/gc.spread.sheets.designer.min.css';
import '@grapecity/spread-sheets-resources-zh';
const spread = ref();
const dialogVisible = ref(false);
const richValue = ref('');
// 处理保存逻辑
const handleSave = () => {
const sheet = spread.value.getActiveSheet();
sheet.suspendPaint();
sheet.getCell(sheet.getActiveRowIndex(), sheet.getActiveColumnIndex()).cellType(new HTMLCellType());
sheet.setValue(sheet.getActiveRowIndex(), sheet.getActiveColumnIndex(), { richText: [{ text: richValue.value }] }, GC.Spread.Sheets.SheetArea.viewport);
sheet.getCell(sheet.getActiveRowIndex(), sheet.getActiveColumnIndex()).wordWrap(true);
sheet.autoFitRow(sheet.getActiveRowIndex());
sheet.resumePaint();
closeModal();
spread.value.focus(true);
};
// 关闭模态框
const closeModal = () => {
dialogVisible.value = false;
richValue.value = '';
spread.value.focus(true);
};
// 进入单元格事件
const onSpreadEnterCell = (sender, args) => {
const rich = args.sheet.getValue(args.row, args.col, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.ValueType.richText);
if (rich !== null && rich !== args.sheet.getValue(args.row, args.col)) {
dialogVisible.value = true;
richValue.value = rich.text;
args.sheet.endEdit(true);
spread.value.focus(false);
}
};
// 初始化
onMounted(() => {
// 初始化电子表格
spread.value = new GC.Spread.Sheets.Workbook(document.getElementById('ss'));
// 绑定双击事件
spread.value.bind(GC.Spread.Sheets.Events.CellDoubleClick, onSpreadEnterCell);
// 添加自定义富文本命令
const commandManager = spread.value.commandManager();
const richTextCommand = {
text: '编辑富文本',
name: 'richText',
command: 'richText',
workArea: 'viewport'
};
commandManager.register('richText', {
canUndo: false,
execute: () => {
dialogVisible.value = true;
spread.value.focus(false);
}
});
spread.value.contextMenu.menuData.push(richTextCommand);
});
function HTMLCellType() {}
HTMLCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
HTMLCellType.prototype.paint = function(ctx, value, x, y, w, h, style, context) {
if (!value) {
return;
}
var DOMURL = window.URL || window.webkitURL || window;
var cell = context.sheet.getCell(context.row, context.col);
var img = cell.tag();
if (img) {
try {
ctx.save();
ctx.rect(x, y, w, h);
ctx.clip();
ctx.drawImage(img, x + 2, y + 2);
ctx.restore();
cell.tag(null);
return;
} catch (err) {
GC.Spread.Sheets.CustomCellType.prototype.paint.apply(this, [ctx, '#HTMLError', x, y, w, h, style, context]);
cell.tag(null);
return;
}
}
var svgPattern =
'<svg xmlns="http://www.w3.org/2000/svg" width="{0}" height="{1}">' +
'<foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="font:{2}">{3}</div></foreignObject></svg>';
var data = svgPattern
.replace('{0}', w)
.replace('{1}', h)
.replace('{2}', style.font)
.replace('{3}', value.text);
var doc = document.implementation.createHTMLDocument('');
doc.write(data);
// Get well-formed markup
data = new XMLSerializer().serializeToString(doc.body.children[0]);
img = new Image();
var svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
var url = DOMURL.createObjectURL(svg);
img.src = url;
cell.tag(img);
img.onload = function() {
context.sheet.repaint(new GC.Spread.Sheets.Rect(x, y, w, h));
};
};
</script>
<style scoped>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.modal-container {
background: #fff;
border-radius: 8px;
padding: 16px;
width: 500px;
max-width: 90%;
max-height: 90%;
overflow: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.modal-title {
font-size: 18px;
font-weight: bold;
}
.modal-close {
background: none;
border: none;
font-size: 18px;
cursor: pointer;
}
.modal-body {
margin-bottom: 16px;
}
.modal-footer {
text-align: center;
}
.modal-btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal-btn {
background: #409eff;
color: #fff;
}
.modal-btn-cancel {
background: #dcdfe6;
color: #fff;
margin-left: 16px;
}
</style> |