Yjs入门

具有强大的共享数据抽象的 CRDT (conflict-free replicated data type 无冲突复制数据类型) 框架。它将其内部数据结构公开为共享类型。

共享类型是常见的数据类型,如具有超能力的 Map 或 Array:更改会自动分发到其他对等体,并在没有合并冲突的情况下进行合并。(带有数据劫持的 shareArray?)

支持许多现有的富文本编辑器、脱机编辑、版本快照、撤消/重做和共享光标。

demosAPI

// demo from  https://docs.yjs.dev/
import * as Y from 'yjs'

const ydoc = new Y.Doc()
const ymap = ydoc.getMap()
ymap.set('keyA', 'valueA')

// 比如服务器?
const ydocRemote = new Y.Doc()
const ymapRemote = ydocRemote.getMap()
ymapRemote.set('keyB', 'valueB')

// Merge changes from remote
const update = Y.encodeStateAsUpdate(ydocRemote)
Y.applyUpdate(ydoc, update)

// Observe that the changes have merged
console.log(ymap.toJSON()) // => { keyA: 'valueA', keyB: 'valueB' }

共享类型

  • Y.Array - 支持在任何位置高效插入/删除元素。内部使用一个链表数组,并在必要时进行拆分。

    • length:number
    • insert(index:number, content:Array<object|boolean|Array|string|number|null|Uint8Array|Y.Type>)
    • push(Array<同 insert 类型>)
    • unshift(Array<同 insert 类型>)
    • delete(index:number, length:number)
    • get(index:number)
    • slice(start:number, end:number):Array<同 insert 类型>
    • forEach(function(value: 同 insert 类型, index:number, array: Y.Array))
    • map(function(T, number, YArray):M):Array<M>
    • toJSON
    • observe(function(YArrayEvent, Transaction):void)
    • unobserve
    • observeDeep
    • unobserveDeep
  • Y.Map

    • size: number
    • set(key:string, value:object|boolean|string|number|null|Uint8Array|Y.Type)
    • get(key:string | index:number)
    • delete(key)
    • has(key)
    • clear()
    • clone():Y.Map
    • toJSON
    • forEach
    • entries
    • values
    • keys
    • observe(function(YMapEvent, Transaction):void)
    • unobserve
    • observeDeep
    • unobserveDeep
  • Y.Text - 服务于富文本,可以转换为 delta 格式。

    • length:number
    • insert(index:number, content:string, [formattingAttributes:Object<string,string>]) => eg: ytext.insert(0, 'bold text', { bold: true })
    • delete(index:number, length:number)
    • format(index:number, length:number, formattingAttributes:Object<string,string>) - 为文本中的区域指定格式属性
    • applyDelta(delta: Delta, opts:Object<string,any>)
    • toString
    • toJSON
    • toDelta
    • observe(function(YTextEvent, Transaction):void)
    • unobserve
    • observeDeep
    • unobserveDeep
  • Y.XmlFragment

  • Y.XmlElement

Y.Doc : const doc = new Y.Doc()

  • clientID - readonly unique id
  • gc - 是否启用垃圾收集。似乎与 undo 相关?
  • transact(function(Transaction):void [, origin:any]) - ??
  • get(string, Y.[TypeClass]):[Type]
  • getArray(string):Y.Array
  • getMap
  • getText
  • getXmlFragment
  • on
  • off
    • on('update', function(updateMessage:Uint8Array, origin:any, Y.Doc):void)
    • on('beforeTransaction', function(Y.Transaction, Y.Doc):void)
    • on('afterTransaction',
    • on('beforeAllTransactions', function(Y.Doc):void)
    • on('afterAllTransactions', function(Y.Doc, Array<Y.Transaction>):void)
  • 合并或更新方法
    • Y.applyUpdate(Y.Doc, update:Uint8Array, [transactionOrigin:any])
    • Y.mergeUpdates(Array<Uint8Array>)
    • Y.diffUpdate(update: Uint8Array, stateVector: Uint8Array): Uint8Array
    • Y.UndoManager
    • ...

https://github.com/yjs/yjs#Shared-Types

y-websocket

maybe https://github.com/y-js/y-websockets-clienthttps://github.com/y-js/y-websockets-server ?

  • 支持跨选项卡通信。当您在同一浏览器中打开同一文档时,文档上的更改将通过跨选项卡通信(Broadcast Channel 和 localStorage 作为回退)进行交换。

  • 支持意识信息的交换(例如光标)。

// Extension for tiptap
import { keymap } from "prosemirror-keymap";
import { Extension } from "tiptap";
import {
  redo,
  undo,
  yCursorPlugin,
  ySyncPlugin,
  yUndoPlugin,
} from "y-prosemirror";
import { WebsocketProvider } from "y-websocket";
import * as Y from "yjs";

const ydoc = new Y.Doc();
const roomname = location.href.includes("uuu") ? "tiptap-demo2" : "tiptap-demo";
const provider = new WebsocketProvider("ws://localhost:8080", roomname, ydoc);
const type = ydoc.getXmlFragment("prosemirror");

provider.on("sync", (isSynced) => {
  console.log("======= sync", isSynced, window.ee.getHTML()); // logs "connected" or "disconnected"
  //   现在没值时进行插入
  if (window.ee.getText() === "")
    window.ee.commands.setContent("<p>Example Text</p>");
});

export default class RealtimeExtension extends Extension {
  get name() {
    return "realtime";
  }

  get plugins() {
    return [
      ySyncPlugin(type),
      yCursorPlugin(provider.awareness),
      yUndoPlugin(),
      keymap({
        "Mod-z": undo,
        "Mod-y": redo,
        "Mod-Shift-z": redo,
      }),
    ];
  }
}
// server by node
const WebSocket = require("ws");
const http = require("http");
const StaticServer = require("node-static").Server;
const setupWSConnection = require("y-websocket/bin/utils.js").setupWSConnection;

const production = process.env.PRODUCTION != null;
const port = process.env.PORT || 8080;

const staticServer = new StaticServer("../", {
  cache: production ? 3600 : false,
  gzip: production,
});

const server = http.createServer((request, response) => {
  request
    .addListener("end", () => {
      staticServer.serve(request, response);
    })
    .resume();
});
const wss = new WebSocket.Server({ server });

wss.on("connection", (conn, req) => setupWSConnection(conn, req, { gc: true }));

server.listen(port);

console.log(
  `Listening to http://localhost:${port} ${production ? "(production)" : ""}`
);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容