自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Yjs + Quill:快速實現(xiàn)支持協(xié)同編輯的富文本編輯器

開源
Y.js 是一個支持 協(xié)同編輯的開源庫。只要我們將自己的數(shù)據(jù)轉(zhuǎn)換為 Y.js 提供的 Y.Array、Y.Map 類型,Y.js 就會自動幫我們做數(shù)據(jù)的一致性處理和同步。

大家好,我是前端西瓜哥,這次來看看 Yjs 如何幫助我們實現(xiàn)協(xié)同編輯能力的。

Y.js 是一個支持 協(xié)同編輯 的開源庫。只要我們將自己的數(shù)據(jù)轉(zhuǎn)換為 Y.js 提供的 Y.Array、Y.Map 類型,Y.js 就會自動幫我們做數(shù)據(jù)的一致性處理和同步。

一致性問題

協(xié)同編輯一個很棘手的問題是:多個用戶同時編輯產(chǎn)生的沖突要怎么處理,如何保證一致性?

比如兩個用戶同時往一個文本的末尾加上不同的字符,最終誰的字符在前,誰的字符在后?

圖片

目前業(yè)界有兩種方案,一個是 OT (Operational transformation)算法,是比較主流的一種解法。流行的開源解決方案是 ShareDB。

它的核心在于 Transform(轉(zhuǎn)換):服務(wù)端接收兩個客戶端的對同一版本數(shù)據(jù)的原子操作行為,轉(zhuǎn)換出它們各自要做的不同操作,然后傳遞給各個客戶端并應(yīng)用,最終讓它們的內(nèi)容是一致的。

圖片

另一種是 CRDT(Conflict-free Replicated Data Type),中文就是 “無沖突復(fù)制數(shù)據(jù)類型”,主要被應(yīng)用在分布式系統(tǒng)中,即可以不需要中心化服務(wù)器。流行的開源方案是 Yjs。

但 CRDT 需要傳輸更多的數(shù)據(jù),有不小的內(nèi)存和性能開銷,且相比 OT 被提出地更晚,學(xué)術(shù)研究相對較少,所以一開始算不上是主流。

然而隨著 Yjs 的出現(xiàn)并做了不少性能優(yōu)化,CRDT 方案也逐漸流行了起來,越來越多新的協(xié)同工具選擇使用 Yjs 來作為數(shù)據(jù)一致性的解決方案。

Yjs 是基于操作的 CRDT,其原理簡單來說,就是記錄所有用戶的操作,這些操作會拼接到一個雙向鏈表中,并通過通用的算法保證確定的順序,最后所有客戶端都能得到相同的一條鏈表,最后得到的數(shù)據(jù)自然也是一致的。

Yjs + Quill:打造協(xié)同工具

我們來寫個 demo 感受一下 Yjs 的強大之處。

先用 vite 搭個普通的不帶框架的腳手架,這里我用的 pnpm,其他包管理工具也行。

pnpm create vite

項目名為 yjs-quill-demo,選擇 Vanilla(不用框架的意思),然后選擇 JavaScript(如果你熟悉 TS,也可以選 TS)

接著是進入文件夾,安裝依賴,并運行。

cd yjs-quill-demo
pnpm install
pnpm run dev

打開瀏覽器輸入控制臺輸出的鏈接,可以看到:

圖片

下面我們來安裝依賴。

首先是開源編輯器 quill 和它的插件 quill-cursors。這個插件可以展示一些其他用戶的光標(biāo)的狀態(tài)。

pnpm add quill quill-cursors

將 mian.js 文件原來的內(nèi)容刪除,加上下面內(nèi)容:

import Quill from 'quill';
import QuillCursors from 'quill-cursors';
import 'quill/dist/quill.snow.css'; // 使用了 snow 主題色

// 使用 cursors 插件
Quill.register('modules/cursors', QuillCursors);

const quill = new Quill(document.querySelector('#app'), {
  modules: {
    cursors: true,
    toolbar: [
      [{ header: [1, 2, false] }],
      ['bold', 'italic', 'underline'],
      ['image', 'code-block'],
    ],
    history: {
      userOnly: true, // 用戶自己實現(xiàn)歷史記錄
    },
  },
  placeholder: '前端西瓜哥...',
  theme: 'snow',
});

效果:

圖片

下面我們就要引入 Yjs,給 quill 加上協(xié)同編輯功能。

Yjs 官方提供了 y-quill 庫,通過它可以將 quill 數(shù)據(jù)模型和 Yjs 數(shù)據(jù)模型進行綁定。

pnpm add yjs y-quill

追加 Yjs 相關(guān)邏輯:

import * as Y from 'yjs';
import { QuillBinding } from 'y-quill';
// ...

const ydoc = new Y.Doc(); // y 文檔對象,保存需要共享的數(shù)據(jù)
const ytext = ydoc.getText('quill'); // 創(chuàng)建名為 quill 的 Text 對象
const binding = new QuillBinding(ytext, quill); // 數(shù)據(jù)模型綁定

ok,接下來就是要接上服務(wù)端,實現(xiàn)數(shù)據(jù)傳輸了。服務(wù)的提供者,Yjs 稱為 provider,大概可以翻譯為 “供應(yīng)者” 的意思。

Yjs 官方提供了幾種 Provider:WebRTC、WebSocket、Dat。

這里我們用比較常見的 WebSocket。

pnpm add y-websocket

代碼:

import { WebsocketProvider } from 'y-websocket';
// ...

// 連接到 websocket 服務(wù)端
const provider = new WebsocketProvider('wss://demos.yjs.dev', 'quill-demo-room', ydoc);
// 數(shù)據(jù)模型綁定,再額外綁上了光標(biāo)對象
const binding = new QuillBinding(ytext, quill, provider.awareness);

這里的服務(wù)器用的是  Yjs 提供的 demo 體驗用的服務(wù)器,因為一些喜聞樂見的原因,可能會連不上這個服務(wù)器。

然后你會發(fā)現(xiàn),如果在同一瀏覽器打開兩個 tab,沒連上服務(wù)也能做協(xié)同編輯。這是因為 Yjs 會優(yōu)先通過瀏覽器的同 host 共享狀態(tài)的方式進行通信,然后才是網(wǎng)絡(luò)通信。所以最好是打開兩個不同的瀏覽器做調(diào)試。

我們驗證一下。

圖片

左邊兩個 tab 頁來自同一個瀏覽器,右邊則是另一個瀏覽器。

當(dāng)修改被我限速為 1 KB/s 的 tab 的編輯器內(nèi)容時,來自同一瀏覽器的另一個 tab 頁立刻發(fā)生了變更(證明通信走的是本地),而另一個瀏覽器的 tab 則慢得多(說明走的網(wǎng)絡(luò)通訊)。

我們也可以自己在本地起一個服務(wù)器,做法是:

HOST=localhost PORT=1234 npx y-websocket

對應(yīng)著要改一下客戶端代碼中 ws 服務(wù)的地址:

const provider = new WebsocketProvider('ws://localhost:1234', 'quill-demo-room', ydoc);

完整代碼

import Quill from 'quill';
import QuillCursors from 'quill-cursors';
import 'quill/dist/quill.snow.css'; // 使用了 snow 主題色
import * as Y from 'yjs';
import { QuillBinding } from 'y-quill';
import { WebsocketProvider } from 'y-websocket';

// 使用 cursors 插件
Quill.register('modules/cursors', QuillCursors);

const quill = new Quill(document.querySelector('#app'), {
  modules: {
    cursors: true,
    toolbar: [
      [{ header: [1, 2, false] }],
      ['bold', 'italic', 'underline'],
      ['image', 'code-block'],
    ],
    history: {
      userOnly: true, // 用戶自己實現(xiàn)歷史記錄
    },
  },
  placeholder: '前端西瓜哥...',
  theme: 'snow',
});

const ydoc = new Y.Doc(); // y 文檔對象,保存需要共享的數(shù)據(jù)
const ytext = ydoc.getText('quill'); // 創(chuàng)建名為 quill 的 Text 對象
// 連接到 websocket 服務(wù)端
const provider = new WebsocketProvider('wss://demos.yjs.dev', 'quill-demo-room', ydoc); 
// 數(shù)據(jù)模型綁定,再綁上光標(biāo)對象
const binding = new QuillBinding(ytext, quill, provider.awareness);

結(jié)尾

因為用了很多 Yjs 提供的模塊化的包,其實我們并沒有接觸到太多的實現(xiàn)細(xì)節(jié),尤其是將數(shù)據(jù)綁定到 Yjs 提供的類型數(shù)據(jù)的實現(xiàn)。只能說是簡單體驗了 Yjs 配合 quill 實現(xiàn)協(xié)同編輯的效果。

責(zé)任編輯:姜華 來源: 前端西瓜哥
相關(guān)推薦

2022-02-15 09:00:18

Vue編輯器字符串

2023-04-17 11:03:52

富文本編輯器MTE

2017-07-27 20:21:06

iOSUITableView富文本編輯器

2016-09-23 20:30:54

Javascriptuiwebview富文本編輯器

2013-11-18 10:08:56

工具免費編程工具

2012-08-10 10:47:45

JavaScript

2022-03-11 08:00:49

編輯器框架Draft.js

2010-03-24 09:20:07

CentOS vi編輯

2018-01-05 14:48:03

前端JavaScript富文本編輯器

2022-04-13 07:38:50

富文本編輯器設(shè)置表格列寬

2020-12-23 22:25:11

Vi文本編輯器Unix

2022-05-13 15:32:11

GNOME文本編輯器

2021-01-07 11:00:59

Sed文本編輯器Linux

2020-04-09 19:07:12

Vuetiptap前端

2009-12-09 10:27:03

VS 2005文本編輯

2011-05-11 10:27:42

文本編輯器

2012-09-29 11:38:27

編程工具文本編輯器編程

2022-01-18 09:35:36

GNOME編輯器Linux

2020-12-29 06:34:55

KDE Plasma文本編輯器

2021-01-21 16:03:15

Java文本編輯器編程語言
點贊
收藏

51CTO技術(shù)棧公眾號