基于tinymce实现多人在线实时协同文本编辑
前言
这可能是最后一次写tinymce相关的文章了,一方面tinymce的底层设计限制了很多功能的实现,另一方面tinymce本身越来越商业化,最新的7版本已经必须配置key,否则面临无法使用的问题。
实时协同
多人在线实时协同文本编辑一直是当前富文本编辑器开发的热点,近十年来几乎所有线上办公的文档编辑软件都实现了这一功能,例如腾讯文档和360云文档等,但是作为开发者,如何在自己开发的软件上实现实时协同编辑,相信这是很多正在使用富文本编辑器开发文档功能的开发者面临的问题。
先上效果
实时协同使用的底层算法有QT和CRDT,这里不展开讲解底层原理,有兴趣的小伙伴可以去自行搜索,我们可以在自己的系统中快速实现协同功能都得益于现成的库——yjs。
yjs的使用
Yjs本身是一个解决冲突的库,对于富文本编辑而言,不同用户在多个客户端编辑的内容一定会产生冲突,例如在同一行同一位置多人一起编辑,内容是否会错乱。Yjs库内部提供了解决冲突的机制,我们调用时只需要将每个用户编辑后的内容传给yjs库,然后拿到yjs库解决冲突后的内容,重新赋值回编辑器内容即可,是不是很简单。
建立中间站-websocket
做到这里的开发者应该很熟悉websocket技术了,这是一种服务端可以主动推送消息给前端页面的一种技术,用来替代古老的轮询机制实现的消息推送。我们需要使用nodejs搭建一个非常简易的websocket服务(当然如果你会java或者有后端可以让后端帮你用其他框架语言搭建)。代码如下,几乎不用解释:
import {
WebSocketServer } from "ws";
// 创建 yjs ws 服务
const yjsws = new WebSocketServer({
port: 1234 });
yjsws.on("connection", (conn, req) => {
console.log(req.url); // 标识每一个连接用户,用于广播不同的文件协同
conn.onmessage = (event) => {
yjsws.clients.forEach((conn) => {
conn.send(event.data);
});
};
conn.on("close", (conn) => {
console.log("yjs 用户关闭连接");
});
});
直接复制就行,缺ws依赖就npm install ws来安装,我安装的ws版本是8.17.1,文件名可以命名为server.js,用node server.js命令启动就可以了。
在编辑器中接入websocket服务
这里还要用到一个库y-websocket,这是一个yjs适配的库。同样使用npm安装就可以。
引入yjs和y-websocket
import * as Y from 'yjs';
import {
WebsocketProvider } from 'y-websocket';
连接websocket服务
const ydoc = new Y.Doc();
const timeId = new Date().getTime();
// 使用 y-websocket 连接到 WebSocket 服务器
const provider = new WebsocketProvider('ws://localhost:1234', `user${
timeId}`, ydoc);
其中ws://localhost:1234就是websocket的地址,端口由上面的server.js里指定。
将复文本内容传到服务端
获取yjs文档
const yText = ydoc.getText('tinymce');
这一步其实是将当前富文本内容,由yjs格式话为yjs需要的数据结构
接下来在tinymce的init中实现其与服务端通信
const init = ref(
{
placeholder: '请输入内容',
language_url: '/tinymce/langs/zh_Hans.js', // 汉化路径
language: 'zh_Hans', // 语言
license_key: 'gpl',
//...省略其他配置
setup: function (editor) {
editor.on('init', () => {
// 当编辑器初始化完成后,设置内容
editor.setContent('');
// 监听编辑器内容变化,并更新 Yjs 文档
editor.on