引言
协同编辑是目前成熟的在线文档编辑软件必备的功能,比如腾讯文档就支持多人协同编辑,现在市面上比较多的两种协同编辑的形式:
第一种,command传递之后信息丢失,需要重写或修改command的,比如复制粘贴功能。
这种类型对应的是希望command生效,但实际上没有生效。
第二种,多人协同所必须的特殊功能,情况比较多:
1. 比如编辑一个单元格时,其他人不允许编辑此单元格,并有样式提醒;
2. A用户正在编辑时,B用户在上方插入了一行,此时A编辑的单元格也要下移,而不是保留在原位;
3. 缩放时不对其他页面有影响;
这种类型对应的是不希望command生效,或者希望改变command生效的效果。
如何解决c【我.爱.线.报.网.】ommand失效的问题
先看下最终的实现效果吧:
<video id=”testId” width=”100%” height=”240″ controls=”controls”><source src=”https://videos.grapecity.com.cn/SpreadJS/online/demos/collaboration-demo.mp4″ type=”video/webm” /> </video>
工程项目目录结构如下:
大家在测试demo前,请务必认真阅读readme文件。
一、向所有客户端同步command
这里用commandManager新增监听的方式来监听所有的操作,并用we【我.爱.线.报.网.】bsocket发送到服务端。马赛克部分为后续其他代码逻辑,暂时不用看。
服务端仅做一个转发:
其他客户端接受到此消息,执行command即可:
到这里,开头提到的快速实现大部分操作的协同就已经完成了,后续的操作都是为了弥补当前方案的不足。
二、处理粘贴
粘贴的command同步到其他客户端时,会执行失败,仔细对比发出的command和接收的command,会发现其中两个字段发生了变化:
这两个数组内部本应该是Range对象,但是却被转换成了不同的Object,这是由于我们使用了JSON.stringify方法,而用此方法序列化时并不支持Range对象,所以我们在客户端接受到此信息时,需要重新将其还原为Ra【我.爱.线.报.网.】nge:
其实你可能会发现当存在fromRanges的时候,我直接用了copyTo方法实现了粘贴,并没有重新执行command,效果其实是一样的。
这里还隐含这另一种情况:从外部复制内容,粘贴到Spread,这时fromRanges对象是不存在的,那么我们就需要执行command了,当然执行之前要把pastedRanges数组的值变为Range类型。
三、编辑状态唯一
即同一个单元格同一时间只能有一个用户编辑。这是协同编辑几乎必备的一个需求,看起来很简单,但事实上是比较复杂的。当客户端有用户开始编辑时,向服务端发送消息,
而服务端需要维护一个数组,记录所有当前正在被编辑的单元格信息,并向所有客户端同步
其【我.爱.线.报.网.】他客户端收到消息后,用户如果要编辑此单元格,则禁止用户进入编辑状态
当然,用户可能希望看到有哪些人正在编辑哪些单元格,类似于这种效果:
这里是用自定义单元格的方案实现的:
这个功能算是初步实现了,但是考虑一下这种情况:如果你正在编辑时,其他用户在上方插入了一行呢?
Lily本来正在编辑A2,Alen在上方插入一行后,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,以上就是这篇文章的【我.爱.线.报.网.】全部内容了,欢迎读者在评论区留下你们的想法~
推荐阅读
友情提醒: 请尽量登录购买,防止付款了不发货!
QQ交流群:226333560 站长微信:qgzmt2