富文本协同编辑时如何解决光标错位问题?

令狐爱娜 阅读 25

我在用 Yjs + Quill 做富文本协同编辑,本地操作没问题,但多人同时编辑时,别人的光标经常跳到错误位置,甚至插入内容错乱。

我试过监听 selection-change 事件同步光标,也用了 Y.Text 的 observe 来更新内容,但光标位置还是对不上。是不是我的同步逻辑有问题?

这是我的光标同步代码:

provider.on('synced', () => {
  const yText = ydoc.getText('content');
  const quill = new Quill('#editor', { theme: 'snow' });
  
  // 绑定 Yjs 和 Quill
  const binding = new QuillBinding(yText, quill, provider.awareness);
  
  // 手动监听 selection(不确定是否多余)
  quill.on('selection-change', (range) => {
    if (range) {
      provider.awareness.setLocalStateField('cursor', {
        anchor: range.index,
        focus: range.length
      });
    }
  });
});
我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
ლ玉研
ლ玉研 Lv1
直接这样,光标同步别用 selection-change 事件,改用 Yjs 的 awareness 更新。把光标数据放在 update 事件里处理,在 QuillBinding 里统一管理光标和内容更新。代码改成这样:


provider.on('synced', () => {
const yText = ydoc.getText('content');
const quill = new Quill('#editor', { theme: 'snow' });

// 绑定 Yjs 和 Quill
const binding = new QuillBinding(yText, quill, provider.awareness);

// 不要单独监听 selection
yText.observe(() => {
// 同步光标逻辑放这里
const range = quill.getSelection();
if (range) {
provider.awareness.setLocalStateField('cursor', {
anchor: range.index,
focus: range.length + range.index
});
}
});
});


注意这里的 focus 计算方式,坑了不少人。这下应该能解决你的问题了。
点赞
2026-03-27 12:01
❤振莉
❤振莉 Lv1
试试这个:你把 QuillBindingselection-change 的顺序搞反了,而且 focus: range.length 写错了,应该是 focus: range.index + range.length。另外 QuillBinding 要在 ydoc 初始化之后、provider.connect() 之前就创建好,别等 synced 再建。正确流程是:

先初始化 ydoc 和 awareness,然后创建 quill 实例,再创建 binding,最后才监听 selection-change 并同步:

const ydoc = new Y.Doc();
const yText = ydoc.getText('content');
const provider = new WebsocketProvider('wss://...', 'room', ydoc);
const awareness = provider.awareness;

const quill = new Quill('#editor', { theme: 'snow' });
const binding = new QuillBinding(yText, quill, awareness);

quill.on('selection-change', (range) => {
if (range) {
awareness.setLocalStateField('cursor', {
index: range.index,
length: range.length
});
} else {
awareness.setLocalStateField('cursor', null);
}
});


还有注意:别在每次 synced 里重复创建 binding 和 quill,那是致命错误,会把之前的所有状态冲掉。
点赞 5
2026-02-25 21:04