中国移动的网站模板,中国商检局做备案网站,wordpress如何直接设置下载,网址升级中引言
协同编辑是目前成熟的在线文档编辑软件必备的功能#xff0c;比如腾讯文档就支持多人协同编辑#xff0c;基本都是采用监听command#xff0c;然后同步此command给其他客户端来实现的#xff0c;例如以下系列#xff1a;
https://gcdn.grapecity.com.cn/showtopic-…引言
协同编辑是目前成熟的在线文档编辑软件必备的功能比如腾讯文档就支持多人协同编辑基本都是采用监听command然后同步此command给其他客户端来实现的例如以下系列
https://gcdn.grapecity.com.cn/showtopic-82517-1-1.html https://gcdn.grapecity.com.cn/showtopic-82518-1-1.html https://gcdn.grapecity.com.cn/showtopic-82519-1-1.html
这种做法可以快速实现大部分功能的协同操作但是也有一些不足我大致将这些不足分为两种类型
第一种command传递之后信息丢失需要重写或修改command的比如复制粘贴功能。
这种类型对应的是希望command生效但实际上没有生效。
第二种多人协同所必须的特殊功能情况比较多
1. 比如编辑一个单元格时其他人不允许编辑此单元格并有样式提醒
2. A用户正在编辑时B用户在上方插入了一行此时A编辑的单元格也要下移而不是保留在原位
3. 缩放时不对其他页面有影响
这种类型对应的是不希望command生效或者希望改变command生效的效果。
如果你也在做协同并且遇到了上述问题那么这篇文章或许可以解答你心中的疑问。
先看下最终的实现效果吧 协同编辑 在开始前先对demo的架构做一个说明我此次写的demo是html做前端并用nodejs做服务端前后端通信采用websocket的方式目录结构如下
大家在测试demo前请务必认真阅读readme文件。
下面我就讲一下如何针对上面提到的几种情况做优化以更好得满足协同的需求整体的思路其实比较简单无非就是对那些不满足需求的command做拦截单独处理。以上提到的情况并不包含实现协同所需的全部功能只是抛砖引玉如果有其他没有考虑到的情况可以用同样的方法处理。
一、向所有客户端同步command
这里用commandManager新增监听的方式来监听所有的操作并用websocket发送到服务端。马赛克部分为后续其他代码逻辑暂时不用看。 服务端仅做一个转发 其他客户端接受到此消息执行command即可 到这里开头提到的快速实现大部分操作的协同就已经完成了后续的操作都是为了弥补当前方案的不足。
二、处理粘贴
粘贴的command同步到其他客户端时会执行失败仔细对比发出的command和接收的command会发现其中两个字段发生了变化 这两个数组内部本应该是Range对象但是却被转换成了不同的Object这是由于我们使用了JSON.stringify方法而用此方法序列化时并不支持Range对象所以我们在客户端接受到此信息时需要重新将其还原为Range 其实你可能会发现当存在fromRanges的时候我直接用了copyTo方法实现了粘贴并没有重新执行command效果其实是一样的。
这里还隐含这另一种情况从外部复制内容粘贴到spread这时fromRanges对象是不存在的那么我们就需要执行command了当然执行之前要把pastedRanges数组的值变为Range类型。
三、编辑状态唯一
即同一个单元格同一时间只能有一个用户编辑。这是协同编辑几乎必备的一个需求看起来很简单但事实上是比较复杂的。当客户端有用户开始编辑时向服务端发送消息 而服务端需要维护一个数组记录所有当前正在被编辑的单元格信息并向所有客户端同步 其他客户端收到消息后用户如果要编辑此单元格则禁止用户进入编辑状态 当然用户可能希望看到有哪些人正在编辑哪些单元格类似于这种效果 这里是用自定义单元格的方案实现的 这个功能算是初步实现了但是考虑一下这种情况如果你正在编辑时其他用户在上方插入了一行呢
Lily本来正在编辑A2Alen在上方插入一行后Lily应该编辑的是A3但是以我们目前的实现方式Lily编辑的仍然是A2。对应的在上方删除行、在左侧插入删除列都会有同样的问题。
这里Lily和Alen两个人都会受到影响Lily编辑的单元格应该移动Alen被锁定的单元格也应该移动而Alen这边比较简单服务端根据插入行列更新锁定单元格信息就好Lily这边则麻烦一些需要记录下Lily已经输入的功能并且在新的单元格打开并开启输入框其中callback函数就是选择新的输入框的逻辑根据不同的状态有所不同所以用回调函数的形式实现。 四、行列变动同步
相信你也注意到在上述处理中行列的变化信息是很重要的在原生command的基础上还要有编辑框的处理逻辑所以行列的变化也需要我们单独来处理在客户端收到行列变化的消息时 做出拦截 并对编辑的框做出正确的移动
结语
到这里这篇文章也接近尾声了整体实现的思路其实比较简单无非就是拦截那些不符合协同需求或者同步时有问题的command并重新实现它们。这种方式能够快速实现简单的协同并且做出定制化的修改。
但是这种方式也存在着一些问题比如无法支持undo堆栈你可以在代码中看到我会随时清空undo堆栈阻止用户进行undoredo操作这是因为用commandManager.execute的方式执行command时一定会进入到堆栈这就导致A用户的操作会出现在B用户的undo堆栈中B用户撤销时就有可能撤销A用户的操作。
除了上面这个问题以外一定还有其他更深、更棘手的问题存在所以要在实际项目中实现协同我的想法是根据业务限制用户的操作类型并对这些有限的操作针对性地开发协同功能这样虽然效率比较低但是由于涉及面小更便于控制。
OK以上就是这篇文章的全部内容了欢迎读者在评论区留下你们的想法~
简单协同代码下载链接
https://gcdn.grapecity.com.cn/forum.php?modattachmentaidMjgzMDk0fGVlNTFkNGQ1fDE2OTA3NjM4Mjl8MHwxNzY0MDU%3D
扩展链接
Spring Boot框架下实现Excel服务端导入导出
项目实战在线报价采购系统React SpreadJSEcharts
Svelte 框架结合 SpreadJS 实现纯前端类 Excel 在线报表设计