天天看點

Svelte架構結合SpreadJS實作表格協同文檔

Svelte架構結合SpreadJS實作表格協同文檔

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,歡迎搜尋并通路葡萄城官網。