SpreadJS 是葡萄城结合 40 余年专业控件技术和在电子表格应用领域的经验而推出的纯前端表格控件。作为一个类 Excel 控件,SpreadJS 如何实现当前比较流行的表格协同呢?本篇文章将简单介绍一下。首先,从框架搭建上,本篇示例采用当下流行的前后端分离的开发方式,前端使用 npm 作为脚手架搭建 Svelte 框架。 后端使用 Java 的 SpringBoot 作为后端框架。前端使用 SpreadJS V15.2.5 以及 SpreadJS 在线表格编辑器 Designer 为前端操作的平台后端使用 GCExcel 作为文档的终端处理,随时提供备份与恢复。首先,介绍下在前端 Svelte 框架下搭建 SpreadJS 在线表格编辑器。1、在 pageage.json 文件中引入相关 SpreadJS 资源
"@grapecity/spread-excelio": "15.2.5", "@grapecity/spread-sheets": "15.2.5", "@grapecity/spread-sheets-barcode": "15.2.5", "@grapecity/spread-sheets-charts": "15.2.5", "@grapecity/spread-sheets-designer": "15.2.5", "@grapecity/spread-sheets-designer-resources-cn": "15.2.5", "@grapecity/spread-sheets-languagepackages": "15.2.5", "@grapecity/spread-sheets-pdf": "15.2.5", "@grapecity/spread-sheets-pivot-addon": "15.2.5", "@grapecity/spread-sheets-pivots": "^14.0.0", "@grapecity/spread-sheets-print": "15.2.5", "@grapecity/spread-sheets-resources-zh": "15.2.5", "@grapecity/spread-sheets-shapes": "15.2.5", "@grapecity/spread-sheets-tablesheet": "15.2.5",
复制代码
2、然后,集成在线表格编辑器 Svelte 组件版。在上一篇文章中,我们介绍了如何在 Svelte 框架中实现在线表格编辑器。我们按照此思路新建一个 SpreadSheet.svelte 文件,写入基础在线表格编辑器。
<script>import {onMount} from 'svelte';import '@grapecity/spread-sheets-print';import "@grapecity/spread-sheets-charts";import '@grapecity/spread-sheets-shapes';import '@grapecity/spread-sheets-pivot-addon';import '@grapecity/spread-sheets-tablesheet';import '@grapecity/spread-sheets-designer-resources-cn';import '@grapecity/spread-sheets-designer';import * as GC from '@grapecity/spread-sheets';import * as GCDesigner from '@grapecity/spread-sheets-designer';
let designer = null;onMount(async () => {designer = new GCDesigner.Spread.Sheets.Designer.Designer(document.getElementById("designerHost"));let spread = designer.getWorkbook();});
</script><div id="designerHost" class="designer-host"></div>
<style scoped>@import "@grapecity/spread-sheets-designer/styles/gc.spread.sheets.designer.min.css";@import '@grapecity/spread-sheets/styles/gc.spread.sheets.excel2013white.css';
.designer-host {width: 100%;height: 100vh;}
</style>
复制代码
3、协同文档可能不止一个,我们需要在页面上创建一个文档列表,来允许用户选择编辑哪个文档,所以我们需要创建一个文档列表页面 OnlineSheets.svelte。在此页面中,我们要实现路由跳转,和加载文档数据。这里我们用了 svelte-spa-router 进行路由跳转 与 isomorphic-fetch 进行前后端数据传输。
<script> import {onMount} from 'svelte'; import { link } from "svelte-spa-router"; import {Utility} from "../utility.js";
let docList = []; onMount(async () => { Utility.getDocList().then(result => { docList = result.map((item,index)=>{ return { path:'/Spreadsheet/' + item.substring(0, item.lastIndexOf('.')), index, fileName:item } }) }); });</script><main class="main"> <table className='table' aria-labelledby="tabelLabel"> <thead> <tr> <th>Document</th> <th></th> </tr> </thead> <tbody> {#each docList as docItem} <tr> <td>{docItem.index}</td> <td>{docItem.fileName}</td> <td className='row'> <a use:link={docItem.path}> Open</a> </td> </tr> {/each} </tbody> </table></main>
复制代码
以上代码实现了文档列表查看与文档跳转,使用<a use:link={docItem.path}> Open</a>将跳转至前面设计好的在线表格编辑器中。至此,前端的相关内容就准备好了,接下来搭建下后端工作。后端的准备工作,首先安装 gradle 作为包管理器。当然,这里也可以用其他工具来代替,例如 maven,或者源生引入 jar 包的方式将需要用到的 jar 包引入进来。之后创建 springboot 工程配合搭建 gradle 引用 GCExcel 以及后面协同需要用到的 websocket。
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><version>2.4.3</version></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.4.3</version></dependency>
<dependency><groupId>com.grapecity.documents</groupId><artifactId>gcexcel</artifactId><version>4.0.3</version></dependency>
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version></dependency>
<dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency>
<dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><version>10.0.2</version></dependency>
<dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>2.5.0</version></dependency></dependencies>
复制代码
这样子,我们做了框架的基本环境搭建,接下来我们介绍下如何搭建 webSocket。在 SpreadSheet.svelte 文件中写入如下代码建立 webSocket 链接:
function connectDocument(docName) { if (webSocket != null) { return; } var ws = new WebSocket(Utility.webSocketUrl); //'ws://localhost:8090/spreadjs' ws.onopen = function () { var data = { cmd: "connect", docID: docName } ws.send(JSON.stringify(data)); } ws.onmessage = onmessage; webSocket = ws; }
复制代码
接下来我们访问下文档列表页,从文档列表页跳转进入文档,进行编辑。
接下来我们需要监听前端发出的操作。这里因为在线表格编辑器本身将所有用户可能做的操作全部做了封装,所以省下了很多的功夫。
onMount(async () => { //初始化Designer designer = new GCDesigner.Spread.Sheets.Designer.Designer(document.getElementById("designerHost")); let spread = designer.getWorkbook(); //fromJSON openDocument(docName); //建立webSocket connectDocument(docName); var cm = spread.commandManager(); cm.addListener('myListener', onCommandExecute) });
复制代码
根据 cmd 去判断并且对命令再做一些简单封装,之后将封装过的命令发到服务端,之后通过 websocket 发同步指令:
function onCommandExecute(args) { console.log(args.command); var command = args.command; var ServerCommand = null;
switch (command.cmd) { case Utility.ServerCommands.EditCell: ServerCommand = { sheetName: command.sheetName, row: command.row, column: command.col, newValue: command.newValue } break; case Utility.ServerCommands.ResizeRow: ServerCommand = { sheetName: command.sheetName, rows: command.rows, size: command.size }; break; case Utility.ServerCommands.ResizeColumn: ServerCommand = { sheetName: command.sheetName, columns: command.columns, size: command.size }; break; case 'Designer.' + Utility.ServerCommands.SetFontFamily: case 'Designer.' + Utility.ServerCommands.SetFontSize: case 'Designer.' + Utility.ServerCommands.SetBackColor: case 'Designer.' + Utility.ServerCommands.SetForeColor: case 'Designer.' + Utility.ServerCommands.SetFontWeight: case 'Designer.' + Utility.ServerCommands.SetFontStyle: case 'Designer.' + Utility.ServerCommands.SetUnderline: case 'Designer.' + Utility.ServerCommands.SetDoubleUnderline: if (command.value && command.value.indexOf('undefined') === -1) { ServerCommand = { sheetName: command.sheetName, selections: command.selections, value: command.value } } break; case Utility.ServerCommands.MoveFloatingObjects: ServerCommand = { sheetName: command.sheetName, floatingObjects: command.floatingObjects, offsetX: command.offsetX, offsetY: command.offsetY }; break; case Utility.ServerCommands.ResizeFloatingObjects: ServerCommand = { sheetName: command.sheetName, floatingObjects: command.floatingObjects, offsetX: command.offsetX, offsetY: command.offsetY, offsetWidth: command.offsetWidth, offsetHeight: command.offsetHeight }; break; case Utility.ServerCommands.InsertColumns: case Utility.ServerCommands.InsertRows: ServerCommand = { sheetName: command.sheetName, selections: command.selections }; break; default: }
if (ServerCommand != null) {
var cmd = command.cmd; var dotIndex = cmd.lastIndexOf('.'); if (dotIndex !== -1) { cmd = cmd.substring(dotIndex + 1); } ServerCommand.cmd = cmd; ServerCommand.docID = params.fileName;
Utility.ExecuteCommandAtServer(ServerCommand);
command.docID = ServerCommand.docID; webSocket.send(JSON.stringify(command)) } }
复制代码
当协同端通过 websocket 接收到请求的时候,使用 onmessage 方法做同步命令。这里在协同端执行 command 之前需要先撤销之前的监听,避免再发送 websocket 导致死循环。在执行之后,再次添加监听。
function onmessage(message) { var command = JSON.parse(message.data); command._styles = null; let spread = designer.getWorkbook() var cm = spread.commandManager(); cm.removeListener('myListener');
spread.commandManager().execute(command);
cm.addListener('myListener', onCommandExecute); }
复制代码
至此,协同基础内容搭建结束,我们来看看编辑单元格内容后,发生了什么吧。如下图所示,修改 E4 单元格内容,同时打开控制台网络 tab。将 E4 单元格数值 2500 改为 2000,此时触发了 EditCell 事件,同时发出了交互指令:

此时新建一个窗口,复制链接,查看文档内容已经变为了2000。如下动图所示:
以上就是Svelte框架结合SpreadJS实现表格协同文档的方法,如果您想体验更多功能或免费下载试用SpreadJS,欢迎访问葡萄城官网。
复制代码
评论