Yjs入门

作者: 我叫Aliya但是被占用了 | 来源:发表于2022-12-08 19:06 被阅读0次

    具有强大的共享数据抽象的 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)" : ""}`
    );
    

    相关文章

      网友评论

          本文标题:Yjs入门

          本文链接:https://www.haomeiwen.com/subject/kwuafdtx.html