Svelte框架实现表格协同文档

news2024/11/24 22:54:44

首先,从框架搭建上,本篇示例采用当下流行的前后端分离的开发方式,前端使用npm作为脚手架搭建Svelte框架。 后端使用Java的SpringBoot作为后端框架。
首先,介绍下在前端Svelte框架下搭建在线表格编辑器。
1、在pageage.json文件中引入相关资源

   "@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>

以上代码实现了文档列表查看与文档跳转,使用 Open将跳转至前面设计好的在线表格编辑器中。
至此,前端的相关内容就准备好了,接下来搭建下后端工作。
后端的准备工作,首先安装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。
如下动图所示:

拓展阅读

React + Springboot + Quartz,从0实现Excel报表自动化

电子表格也能做购物车?简单三步就能实现

使用纯前端类Excel表格控件SpreadJS构建企业现金流量表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ANR问题分析

ANR概念 anr是指应用程序无响应&#xff0c;Android系统对于一些事件需要在一定时间范围内完成&#xff0c;如果超过预定时间未能得到有效响应或者响应时间过长&#xff0c;都会造成anr。通常发生anr时&#xff0c;系统会弹出一个提示框&#xff0c;让用户知道&#xff0c;该程…

AppScan介绍和安装

第一节-AppScan介绍和安装 1.简介 Appscan 10中文版是是全新网络安全漏洞扫描软件&#xff0c;软件可以直接可以对OS命令、SSRF和XXE攻击等漏洞进行检测&#xff0c;使得漏洞检测更加容易&#xff0c;提高漏洞的扫描效率。软件同时支持动态、静态、互动分析三种不同的测试功能…

OVN实验----NAT

概述 在L2互通、L3互通实验基础上通过NAT实现访问公网。 架构图如下&#xff0c; 这里两台逻辑路由器LR1和GLR是通过一台逻辑交换机LSjoin互连的&#xff0c; GLR和物理网络设备通过LSlocal相连。 物理拓扑 如上一个实验OVN实验----L2互通 逻辑拓扑 配置 开始实验前先检查…

设计模式之装饰者模式

装饰者模式 定义 先上定义&#xff1a;指在不改变现有对象结构的情况下&#xff0c;动态地给该对象增加一些职责&#xff08;即增加其额外功能&#xff09;的模式。 优缺点 优点&#xff1a; 1&#xff0c;装饰器是继承的有力补充&#xff0c;比继承灵活&#xff0c;在不改…

【进阶C语言】文件操作

文章目录一.文件1.文件的功能2.文件的分类3.文件路径绝对路径相对路径4.文件信息区5.文件缓冲区6.流的概念7.输入输出二.文件函数1.打开与关闭文件打开文件——fopen返回类型参数关闭文件——fclose返回类型参数2. 顺序读写1.输入输出字符输入字符函数——fgetc返回类型函数参数…

新享科技UniPro将敏捷理念数字化 助力企业迎接2023

2023年新年伊始&#xff0c;“复苏”和“希望”成了越来越多国内企业和消费者的直接感受&#xff0c;与此同时&#xff0c;国际经济也从疫情中缓慢“恢复”过来&#xff0c;特斯拉在中国区掀起了新一轮降价风潮&#xff0c;而行业“销冠”比亚迪却高调发布了百万级新车。如同晴…

websocket显示实时消息

websocket实现实时消息展示 前面介绍过websocket聊天功能的实现,不清楚的可以先看下 websocket实现在线聊天 https://blog.csdn.net/qq_51076413/article/details/124644500 之前发过websocket的相关使用和一对一聊天的demo代码&#xff0c;这里是针对上几篇文章的补充&#x…

Nacos服务注册与发现源码剖析

文章目录前提介绍Nacos源码下载Nacos客户端源码Spring Cloud Starter Nacos 源码Nacos服务端源码前提介绍 服务注册与发现作用主要是为了更好的管理众多的服务&#xff0c;不论Nacos还是Zookeeper、Eureka&#xff0c;作为注册中心都是为了解决以下两个问题&#xff1a; 屏蔽…

【论文写作】英文写作工具推荐及使用教程:DeepL(翻译) + EasyEssay(扩写) + QuillBot(改写润色)

文章目录一、DeepL二、EasyEssay2.1 润写2.2 扩写2.3 生成文章2.4 英文查重三、QuillBot一、DeepL DeepL官网 DeepL的主要作用是翻译&#xff0c;一开始我也是在B站上看到有人推荐用这款翻译工具的&#xff0c;抱着试一试的心态去用了一下&#xff0c;感觉翻译效果真的很不错&a…

【贪心】AcWing 803. 区间选点

905. 区间选点 文章目录题目描述输入格式&#xff1a;输出格式&#xff1a;数据范围输入样例输出样例方法&#xff1a;贪心解题思路代码复杂度分析&#xff1a;题目描述 给定 N 个闭区间 [ai,bi][a_i,b_i][ai​,bi​]&#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每…

利用时间序列预测电量,冷量和压缩空气量

利用时间序列预测电量&#xff0c;冷量和压缩空气量背景分析与思路代码结果一&#xff0c;电量预测二&#xff0c;冷量预测三&#xff0c;压缩空气预测调优一&#xff0c;电量预测(m6)二&#xff0c;冷量预测三&#xff0c;压缩空气预测背景 根据提供的数据&#xff0c;详见附…

企业开发项目【1】— — 流程、开发环境搭建模板

企业开发项目【1】— — 流程、开发环境搭建模板 以黑马的学成在线为例 1 项目背景 2 项目介绍 3 开发环境搭建 3.1 开发工具配置&#xff08;后端&#xff09; 3.1.1 Idea配置 环境编码 编译级别配置 project structure - 设置JDK版本和编译级别3. 自动导包设置 IDEA可以…

远距离车载高速网络通讯方案

一 车载网络的发展 随着电子、半导体和通讯等行业的快速发展&#xff0c;汽车智能化的诉求也愈发强烈。越来越多的传感器和处理器的应用推动了汽车的智能化和电气化&#xff0c;与此同时&#xff0c;也使得ECU&#xff08;电子控制单元&#xff09;的数量快速增加。随着自动驾…

基于“python+”潮汐、风驱动循环、风暴潮等海洋水动力模拟

ADCIRC是新一代海洋水动力计算模型&#xff0c;它采用了非结构三角形网格广义波动连续方程的设计&#xff0c;在提高计算精确度的同时还减小了计算时间。被广泛应用于&#xff1a;模拟潮汐和风驱动的循环、预测风暴潮和洪水和近岸海上作业等。 除此之外&#xff0c;ADCIRC也是我…

目前市场上比较好的oa办公系统企业管理软件有哪些?

行政小李拿着《疫情期间春节返乡填报单》在工位之间来回穿梭…… 财务小王把年终奖金和福利方法拿给老板签字…… 行政小李的和人事小赵回回都因为入职新人培训的事情扯皮…… 后勤小郑每次办公物资的整理都要做半天…… OA系统本就是为企业内部的员工沟通、工作效率提高、协作…

WebDAV之葫芦儿·派盘+BookxNote

BookxNote 支持WebDAV方式连接葫芦儿派盘。 BookxNote是全新设计的电子书阅读学习笔记软件,以不同的思维方式重塑我们的学习过程。一边阅读一边划重点,提供多种划重点笔记工具,包括直线、矩形、圆形、高亮文本,图片摘录。高亮的文本自动编辑为重点的批注内容,还可以对重点…

查看网站历史记录的2种办法,怎样查看网站历史记录?

有个想购买二手域名的朋友问小黑&#xff1a;如何查看网站历史记录&#xff1f;于是今天就分享查看网站历史记录的 2种办法&#xff1a;网站历史记录和快照。 如果你在下单之前想查一查域名以前做过些什么&#xff0c;有没有违禁记录&#xff0c;被惩罚过&#xff0c;被K过等等…

LeetCode082_82. 删除排序链表中的重复元素 II

LeetCode082_82. 删除排序链表中的重复元素 II 一、描述 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;…

CODESYS开发教程8-定时、触发和计数

今天继续我们的小白教程&#xff0c;老鸟就不要在这浪费时间了&#x1f60a;。 前面一期我们介绍了CODESYS的字符串及其操作。这一期主要介绍CODESYS的定时器及触发的相关功能块特性及用法&#xff0c;注意本文介绍的定时器、触发器和计数器均包含在CODESYS的Standard库中。 一…

c-note:字符串常量初始化存放位置

两行代码&#xff0c;分别以数组形式和指针形式&#xff0c;先说结论。 对于字面量"he"的存放位置&#xff1a; 1、数组形式&#xff0c;字面量直接存放进栈给temp处开辟的空间 2、指针形式&#xff0c;字面量"he"是一个常量&#xff0c;在编译之初便存在于…