univer实现excel协同

快速入门

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://unpkg.com/@univerjs/umd/lib/univer.full.umd.js"></script><script src="https://unpkg.com/@univerjs/umd/lib/locale/zh-CN.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs/umd/lib/univer.css"><style>#app{width: 100%;height: 100vh;}</style>
</head>
<body><div id="app"></div><script>var {UniverCore,UniverDesign,UniverEngineRender,UniverEngineFormula,UniverDocs,UniverDocsUi,UniverUi,UniverSheets,UniverSheetsUi,UniverSheetsNumfmt,UniverSheetsFormula,UniverFacade,} = windowvar univer = new UniverCore.Univer({theme: UniverDesign.defaultTheme,locale: UniverCore.LocaleType.ZH_CN,locales: {[UniverCore.LocaleType.ZH_CN]: UniverUMD['zh-CN'],},});univer.registerPlugin(UniverEngineRender.UniverRenderEnginePlugin);univer.registerPlugin(UniverEngineFormula.UniverFormulaEnginePlugin);univer.registerPlugin(UniverUi.UniverUIPlugin, {container: "app",});univer.registerPlugin(UniverDocs.UniverDocsPlugin);univer.registerPlugin(UniverDocsUi.UniverDocsUIPlugin);univer.registerPlugin(UniverSheets.UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUi.UniverSheetsUIPlugin);univer.registerPlugin(UniverSheetsNumfmt.UniverSheetsNumfmtPlugin);univer.registerPlugin(UniverSheetsFormula.UniverSheetsFormulaPlugin);univer.createUnit(UniverCore.UniverInstanceType.UNIVER_SHEET, {})const univerAPI = UniverFacade.FUniver.newAPI(univer)</script>
</body>
</html>

在这里插入图片描述

使用univer后端服务协同

后端部署

bash -c "$(curl -fsSL https://get.univer.ai)"

在这里插入图片描述
打开链接获取token,后续的安装就开始了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
访问8000

curl http://127.0.0.1:8000

在这里插入图片描述

如果机器停止了,重启之后可以运行docker compose up启动

页面部署

说明服务启动起来了,引入js库尝试,发现报错

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://unpkg.com/@univerjs/umd/lib/univer.full.umd.js"></script><script src="https://unpkg.com/@univerjs/umd/lib/locale/zh-CN.js"></script><script src="https://unpkg.com/@univerjs-pro/collaboration/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/collaboration-client/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs/umd/lib/univer.css"><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/collaboration-client/lib/index.css"><style>#app {width: 100%;height: 100vh;}</style>
</head><body><div id="app"></div><script>var {UniverCore,UniverDesign,UniverEngineRender,UniverEngineFormula,UniverDocs,UniverDocsUi,UniverUi,UniverSheets,UniverSheetsUi,UniverSheetsNumfmt,UniverSheetsFormula,UniverFacade,UniverCollaborationPlugin,UniverCollaborationClientPlugin} = windowvar univer = new UniverCore.Univer({theme: UniverDesign.defaultTheme,locale: UniverCore.LocaleType.ZH_CN,locales: {[UniverCore.LocaleType.ZH_CN]: UniverUMD['zh-CN'],},});univer.registerPlugin(UniverEngineRender.UniverRenderEnginePlugin);univer.registerPlugin(UniverEngineFormula.UniverFormulaEnginePlugin);univer.registerPlugin(UniverUi.UniverUIPlugin, {container: "app",});univer.registerPlugin(UniverDocs.UniverDocsPlugin);univer.registerPlugin(UniverDocsUi.UniverDocsUIPlugin);univer.registerPlugin(UniverSheets.UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUi.UniverSheetsUIPlugin);univer.registerPlugin(UniverSheetsNumfmt.UniverSheetsNumfmtPlugin);univer.registerPlugin(UniverSheetsFormula.UniverSheetsFormulaPlugin);univer.registerPlugin(UniverCollaborationPlugin);univer.registerPlugin(UniverCollaborationClientPlugin, {authzUrl: 'http://192.168.56.10:8000/universer-api/authz',snapshotServerUrl: 'http://192.168.56.10:8000/universer-api/snapshot',collabSubmitChangesetUrl: 'http://192.168.56.10:8000/universer-api/comb',collabWebSocketUrl: 'ws://192.168.56.10:8000/universer-api/comb/connect',});univer.createUnit(UniverCore.UniverInstanceType.UNIVER_SHEET, {})const univerAPI = UniverFacade.FUniver.newAPI(univer)</script>
</body></html>

在这里插入图片描述

vue3部署

采用vue3方式开发

 pnpm initpnpm create vite --registry=http://registry.npm.taobao.org

在这里插入图片描述

pnpm install --registry=http://registry.npm.taobao.org
pnpm run dev

安装依赖包

pnpm add @univerjs/core @univerjs/design @univerjs/docs @univerjs/docs-ui @univerjs/engine-formula @univerjs/engine-render @univerjs/sheets @univerjs/sheets-formula @univerjs/sheets-ui @univerjs/ui --registry=http://registry.npm.taobao.orgpnpm add @univerjs/facade --registry=http://registry.npm.taobao.org

在这里插入图片描述
在这里插入图片描述
修改App.vue

<template><div ref="excelContent" style="width: 100%;height: 900px;"></div>
</template>
<script setup lang="ts">import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";import { onMounted, ref } from 'vue'
import { LocaleType, Tools, Univer, UniverInstanceType } from "@univerjs/core";
import { defaultTheme } from "@univerjs/design";import { UniverFormulaEnginePlugin } from "@univerjs/engine-formula";
import { UniverRenderEnginePlugin } from "@univerjs/engine-render";import { UniverUIPlugin } from "@univerjs/ui";import { UniverDocsPlugin } from "@univerjs/docs";
import { UniverDocsUIPlugin } from "@univerjs/docs-ui";import { UniverSheetsPlugin } from "@univerjs/sheets";
import { UniverSheetsFormulaPlugin } from "@univerjs/sheets-formula";
import { UniverSheetsUIPlugin } from "@univerjs/sheets-ui";import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import { FUniver } from '@univerjs/facade'const excelContent = ref<HTMLElement | null>(null)onMounted(() => {initSheet()
})const initSheet = () => {const univer = new Univer({theme: defaultTheme,locale: LocaleType.ZH_CN,locales: {[LocaleType.ZH_CN]: Tools.deepMerge(SheetsZhCN,DocsUIZhCN,SheetsUIZhCN,SheetsFormulaZhCN,UIZhCN,DesignZhCN,),},});univer.registerPlugin(UniverRenderEnginePlugin);univer.registerPlugin(UniverFormulaEnginePlugin);univer.registerPlugin(UniverUIPlugin, {container: excelContent.value!,});univer.registerPlugin(UniverDocsPlugin);univer.registerPlugin(UniverDocsUIPlugin);univer.registerPlugin(UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUIPlugin);univer.registerPlugin(UniverSheetsFormulaPlugin);univer.createUnit(UniverInstanceType.UNIVER_SHEET, {});const univerAPI = FUniver.newAPI(univer)
}</script>
<style scoped>
.excel-container {width: 100%;height: 100%;min-height: 90vh;
}
</style>

启动项目查看效果
在这里插入图片描述

协同编辑

pnpm add @univerjs-pro/collaboration @univerjs-pro/collaboration-client --registry=http://registry.npm.taobao.org

在这里插入图片描述
修改App.vue

<template><div ref="excelContent" style="width: 100%;height: 900px;"></div>
</template>
<script setup lang="ts">import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";
import '@univerjs-pro/collaboration-client/lib/index.css';import { onMounted, ref } from 'vue'
import { LocaleType, Tools, Univer, UniverInstanceType,IAuthzIoService,IUndoRedoService } from "@univerjs/core";
import { defaultTheme } from "@univerjs/design";import { UniverFormulaEnginePlugin } from "@univerjs/engine-formula";
import { UniverRenderEnginePlugin } from "@univerjs/engine-render";import { UniverUIPlugin } from "@univerjs/ui";import { UniverDocsPlugin } from "@univerjs/docs";
import { UniverDocsUIPlugin } from "@univerjs/docs-ui";import { UniverSheetsPlugin } from "@univerjs/sheets";
import { UniverSheetsFormulaPlugin } from "@univerjs/sheets-formula";
import { UniverSheetsUIPlugin } from "@univerjs/sheets-ui";import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import { FUniver } from '@univerjs/facade'import { UniverCollaborationPlugin } from '@univerjs-pro/collaboration';
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client';
import CollaborationClientZhCN from '@univerjs-pro/collaboration-client/locale/zh-CN';const excelContent = ref<HTMLElement | null>(null)onMounted(() => {initSheet()
})const initSheet = () => {const univer = new Univer({// 通过将 override 选项设置为 [[IAuthzIoService, null]],可以告诉 Univer 不要注册内置的 IAuthzIoService。// 通过将 override 选项设置为 [[IUndoRedoService, null]],可以告诉 Univer 不要注册内置的 IUndoRedoService// 这样,Univer 将使用 UniverCollaborationPlugin 中提供的服务作为权限、重做恢复服务的实现。override: [[IAuthzIoService,null],[IUndoRedoService,null],],theme: defaultTheme,locale: LocaleType.ZH_CN,locales: {[LocaleType.ZH_CN]: Tools.deepMerge(SheetsZhCN,DocsUIZhCN,SheetsUIZhCN,SheetsFormulaZhCN,UIZhCN,DesignZhCN,CollaborationClientZhCN),},});univer.registerPlugin(UniverRenderEnginePlugin);univer.registerPlugin(UniverFormulaEnginePlugin);univer.registerPlugin(UniverUIPlugin, {container: excelContent.value!,});univer.registerPlugin(UniverDocsPlugin);univer.registerPlugin(UniverDocsUIPlugin);univer.registerPlugin(UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUIPlugin);univer.registerPlugin(UniverSheetsFormulaPlugin);univer.registerPlugin(UniverCollaborationPlugin);univer.registerPlugin(UniverCollaborationClientPlugin, {authzUrl: 'http://192.168.56.10:8000/universer-api/authz',snapshotServerUrl: 'http://192.168.56.10:8000/universer-api/snapshot',collabSubmitChangesetUrl: 'http://192.168.56.10:8000/universer-api/comb',collabWebSocketUrl: 'ws://192.168.56.10:8000/universer-api/comb/connect',});univer.createUnit(UniverInstanceType.UNIVER_SHEET, {});const univerAPI = FUniver.newAPI(univer)if(univerAPI){console.log("univerAPI")}
}</script>
<style scoped>
.excel-container {width: 100%;height: 100%;min-height: 90vh;
}
</style>

在这里插入图片描述

一直离线状态,没搞清楚原因

把官方的例子跑起来了,说明后端是没有问题的
在这里插入图片描述

代码如下

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Univer UMD With Collaboration, Live Share, Print, Exchange</title><script src="https://unpkg.com/@univerjs/umd/lib/univer.full.umd.js"></script><script src="https://unpkg.com/@univerjs/umd/lib/locale/zh-CN.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs/umd/lib/univer.css"><script src="https://unpkg.com/@univerjs-pro/license/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/collaboration/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/collaboration-client/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/collaboration-client/lib/index.css"><script src="https://unpkg.com/@univerjs-pro/live-share/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/live-share/lib/index.css"><script src="https://unpkg.com/@univerjs-pro/print/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/sheets-print/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/sheets-print/lib/index.css"><script src="https://unpkg.com/@univerjs-pro/exchange-client/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/exchange-client/lib/index.css"><script src="https://unpkg.com/@univerjs-pro/sheets-exchange-client/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/engine-pivot/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/sheets-pivot/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/sheets-pivot-ui/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/sheets-pivot-ui/lib/index.css"><script src="https://unpkg.com/@univerjs-pro/edit-history-viewer/lib/umd/index.js"></script><script src="https://unpkg.com/@univerjs-pro/edit-history-loader/lib/umd/index.js"></script><link rel="stylesheet" href="https://unpkg.com/@univerjs-pro/edit-history-viewer/lib/index.css"><style>body {margin: 0;padding: 0;font-family: Arial, sans-serif;}#app {height: 100vh;width: 100vw;}</style></head><body><div id="app"></div><script>var {UniverCore,UniverDesign,UniverEngineRender,UniverEngineFormula,UniverDocs,UniverDocsUi,UniverUi,UniverSheets,UniverSheetsUi,UniverSheetsNumfmt,UniverCollaboration,UniverCollaborationClient,UniverSheetsThreadComment,UniverExchangeClient,UniverFacade} = window;var { UniverSheetsFormulaPlugin } = UniverSheetsFormula;var { UniverSheetsExchangeClientPlugin } = UniverSheetsExchangeClient;var { UniverSheetsNumfmtPlugin } = UniverSheetsNumfmt;var { UniverDocsPlugin } = UniverDocs;var { UniverRenderEnginePlugin } = UniverEngineRender;var { UniverFormulaEnginePlugin } = UniverEngineFormula;var { UniverUIPlugin } = UniverUi;var { UniverDocsUIPlugin } = UniverDocsUi;var { UniverSheetsPlugin } = UniverSheets;var { UniverSheetsUIPlugin } = UniverSheetsUi;var { UniverSheetsPivotTablePlugin } = UniverSheetsPivot;var { UniverSheetsPivotTableUIPlugin } = UniverSheetsPivotUi;var { UniverEditHistoryLoaderPlugin } = UniverEditHistoryLoader;var { UniverCollaborationPlugin } = UniverCollaboration;var { UniverCollaborationClientPlugin } = UniverCollaborationClient;var { UniverLiveSharePlugin } = UniverLiveShare;var { UniverSheetsPrintPlugin } = UniverSheetsPrint;var { UniverSheetsThreadCommentPlugin, IThreadCommentMentionDataService } = UniverSheetsThreadComment;var { defaultTheme, greenTheme } = UniverDesign;var { FUniver } = UniverFacade;var { UniverExchangeClientPlugin }= UniverExchangeClient;var {UniverLicensePlugin} = UniverLicense;var {UniverInstanceType,Tools,IUndoRedoService,IAuthzIoService,LocaleType,Univer,IConfigService} = window.UniverCore;</script><script>// 你好,开发者,这是一个简单的示例,展示如何使用 Univer UMD 实现协作、实时共享、打印和导入导出功能// 如果你想使用协作、实时共享、打印和交换功能,你需要配置 `universerEndpoint`// `universerEndpoint` 是提供协作、实时共享、打印和交换服务的 Univer 后端服务器地址// 你可以在自己的服务器上部署 Univer 服务器,详见部署指南:https://univer.ai/zh-CN/guides/sheet/server/dockerconst universerEndpoint = '192.168.56.10:8000';// 协同插件从 URL 中获取 unit 参数,如果没有 unit 参数,则创建一个新的 unitconst url = new URL(window.location.href)const unit = url.searchParams.get('unit')if (unit) {// 加载协作、打印、交换的国际化资源Promise.all([fetch('https://unpkg.com/@univerjs-pro/collaboration-client/lib/locale/zh-CN.json').then(res => res.json()),fetch('https://unpkg.com/@univerjs-pro/sheets-print/lib/locale/zh-CN.json').then(res => res.json()),fetch('https://unpkg.com/@univerjs-pro/exchange-client/lib/locale/zh-CN.json').then(res => res.json()),fetch('https://unpkg.com/@univerjs-pro/edit-history-viewer/lib/locale/zh-CN.json').then(res => res.json()),fetch('https://unpkg.com/@univerjs-pro/sheets-pivot/lib/locale/zh-CN.json').then(res => res.json()),fetch('https://unpkg.com/@univerjs-pro/sheets-pivot-ui/lib/locale/zh-CN.json').then(res => res.json()),]).then((langs) => {setup(Tools.deepMerge(UniverUMD['zh-CN'],...langs));})} else {const { UniverInstanceType } = window.UniverCore;fetch(`http://${universerEndpoint}/universer-api/snapshot/${UniverInstanceType.UNIVER_SHEET}/unit/-/create`, {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({type: UniverInstanceType.UNIVER_SHEET,name: 'New Sheet By Univer',creator: 'user',}),}).then((response) => {if (!response.ok) {throw new Error('Failed to create new sheet')}return response.json()}).then((data) => {if (!data.unitID) {throw new Error('create unit failed')}url.searchParams.set('unit', data.unitID)url.searchParams.set('type', String(UniverInstanceType.UNIVER_SHEET))window.location.href = url.toString()}).catch((error) => {console.error(error)})}const setup = (locales) => {var univer = new Univer({theme: defaultTheme,locale: LocaleType.ZH_CN,locales:{[LocaleType.ZH_CN]: locales,},override: [[IAuthzIoService, null],[IUndoRedoService, null]]});univer.registerPlugin(UniverRenderEnginePlugin);univer.registerPlugin(UniverDocsPlugin);univer.registerPlugin(UniverFormulaEnginePlugin);univer.registerPlugin(UniverSheetsFormulaPlugin);univer.registerPlugin(UniverUIPlugin, {container: "app",});univer.registerPlugin(UniverDocsUIPlugin);univer.registerPlugin(UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUIPlugin);const mockUser = {userID: 'mockId',name: 'MockUser',avatar: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAInSURBVHgBtZU9TxtBEIbfWRzFSIdkikhBSqRQkJqkCKTCFkqVInSUSaT0wC8w/gXxD4gU2nRJkXQWhAZowDUUWKIwEgWWbEEB3mVmx3dn4DA2nB/ppNuPeWd29mMIPXDr+RxwtgRHeW6+guNPRxogqnL7Dwz9psJ27S4NShaeZTH3kwXy6I81dlRKcmRui88swdq9AcSFL7Buz1Vmlns64MiLsCjzwnIYHLH57tbfFbs7KRaXyEU8FVZofqccOfA5l7Q8LPIkGrwnb2RPNEXWFVMUF3L+kDCk0btDDAMzOm5YfAHDwp4tG74wnzAsiOYMnJ3GoDybA7IT98/jm5+JNnfiIzAS6LlqHQBN/i6b2t/cV1Hh6BfwYlHnHP4AXi5q/8kmMMpOs8+BixZw/Fd6xUEHEbnkgclvQP2fGp7uShRKnQ3G32rkjV1th8JhIGG7tR/JyjGteSOZELwGMmNqIIigRCLRh2OZIE6BjItdd7pCW6Uhm1zzkUtungSxwEUzNpQ+GQumtH1ej1MqgmNT6vwmhCq5yuwq56EYTbgeQUz3yvrpV1b4ok3nYJ+eYhgYmjRUqErx2EDq0Fr8FhG++iqVGqxlUJI/70Ar0UgJaWHj6hYVHJrfKssAHot1JfqwE9WVWzXZVd5z2Ws/4PnmtEjkXeKJDvxUecLbWOXH/DP6QQ4J72NS0adedp1aseBfXP8odlZFfPvBF7SN/8hky1TYuPOAXAEipMx15u5ToAAAAABJRU5ErkJggg==',anonymous: false,canBindAnonymous: false,};class CustomMentionDataService {trigger = '@';async getMentions (search) {return [{id: mockUser.userID,label: mockUser.name,type: 'user',icon: mockUser.avatar,},{id: '2',label: 'User2',type: 'user',icon: mockUser.avatar,},];}}univer.registerPlugin(UniverSheetsThreadCommentPlugin, {overrides: [[IThreadCommentMentionDataService, { useClass: CustomMentionDataService }]],});// 注册协同插件univer.registerPlugin(UniverCollaborationPlugin);univer.registerPlugin(UniverCollaborationClientPlugin, {authzUrl: `http://${universerEndpoint}/universer-api/authz`,snapshotServerUrl: `http://${universerEndpoint}/universer-api/snapshot`,collabSubmitChangesetUrl: `http://${universerEndpoint}/universer-api/comb`,collabWebSocketUrl: `ws://${universerEndpoint}/universer-api/comb/connect`,// 如果你使用了导入导出插件,需要配置以下参数uploadFileServerUrl: `http://${universerEndpoint}/universer-api/stream/file/upload`,signUrlServerUrl: `http://${universerEndpoint}/universer-api/file/{fileID}/sign-url`,});// 注册实时共享插件univer.registerPlugin(UniverLiveSharePlugin)// 注册打印插件univer.registerPlugin(UniverSheetsPrintPlugin)// 注册导入导出插件univer.registerPlugin(UniverExchangeClientPlugin, {uploadFileServerUrl: `http://${universerEndpoint}/universer-api/stream/file/upload`,importServerUrl: `http://${universerEndpoint}/universer-api/exchange/{type}/import`,exportServerUrl: `http://${universerEndpoint}/universer-api/exchange/{type}/export`,getTaskServerUrl: `http://${universerEndpoint}/universer-api/exchange/task/{taskID}`,signUrlServerUrl: `http://${universerEndpoint}/universer-api/file/{fileID}/sign-url`,})univer.registerPlugin(UniverSheetsExchangeClientPlugin)}</script></body></html>

使用websocket协同

pnpm init
pnpm add ws --registry=http://registry.npm.taobao.org

修改package.json

{"name": "server","version": "1.0.0","description": "","main": "index.js","scripts": {"dev": "node index.js"},"keywords": [],"author": "","license": "ISC","dependencies": {"ws": "^8.18.0"}
}

新建index.js

//创建一个WebSocket服务器,在8080端口启动
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8089 });
console.log("websocket服务器启动于:localhost:8089");// 监听前端连接websocket(ws.on的connection事件)
server.on('connection', function connection(ws, req) {const ip = req.socket.remoteAddress;const port = req.socket.remotePort;const clientName = ip + port;console.log('%s 连接了', clientName);ws.on('message', (msg = {}) => {console.log('客户端发送给服务器端', msg.toString('utf8'));// 由服务端往客户端发送数据server.clients.forEach((client) => {//console.log(client, 'client');client.send(msg);});});
});
//只要有WebSocket连接到该服务器,就会触发'connection'事件;req对象可以用来获取客户端的信息,如ip、端口号
//获取所有已连接的客户端信息,则可以使用server.clients数据集// 服务器接收数据(ws.on的message事件)
// module.exports.listener = () => {
//   server.on('connection', (ws, req) => {
//     console.log('有客户端连接成功了', ws, req);//     // 对客户端的连接对象进行message事件的监听
//     // 当客户端有消息发送给服务器时,服务器就能够触发该消息
//     // msg:由客户端发给服务端的数据
//     ws.on('message', (msg = {}) => {
//       console.log('客户端发送给服务器端', msg);
//       // 当接收到客户端传的参数之后服务器端可以执行某些操作(具体看需求)
//       // 小编这里是做了一个数据返回给客户端
//       // 是当客户端连接成功之后会发送一条信息告诉服务器,服务器监听到信息之后再返回数据给客户端//       // 由服务端往客户端发送数据
//       server.clients.forEach((client) => {
//         console.log(client, 'client');
//         // client.send(JSON.stringify(info));
//         client.send(msg);
//       });
//     });
//   });
// };

把websocket启动起来

pnpm run dev

前端参考vue3搭建起来,然后修改App.vue

<template><div id="excelContent" style="width: 100%;height: 900px;"></div>
</template><script setup lang="ts">
import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";import { onMounted, ref } from 'vue'
import { LocaleType, Tools, Univer, UniverInstanceType } from "@univerjs/core";
import { defaultTheme } from "@univerjs/design";import { UniverFormulaEnginePlugin } from "@univerjs/engine-formula";
import { UniverRenderEnginePlugin } from "@univerjs/engine-render";import { UniverUIPlugin } from "@univerjs/ui";import { UniverDocsPlugin } from "@univerjs/docs";
import { UniverDocsUIPlugin } from "@univerjs/docs-ui";import { UniverSheetsPlugin } from "@univerjs/sheets";
import { UniverSheetsFormulaPlugin } from "@univerjs/sheets-formula";
import { UniverSheetsUIPlugin } from "@univerjs/sheets-ui";import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import { FUniver } from '@univerjs/facade'onMounted(() => {initSheet()
})const initSheet = () => {const univer = new Univer({theme: defaultTheme,locale: LocaleType.ZH_CN,locales: {[LocaleType.ZH_CN]: Tools.deepMerge(SheetsZhCN,DocsUIZhCN,SheetsUIZhCN,SheetsFormulaZhCN,UIZhCN,DesignZhCN,),},});univer.registerPlugin(UniverRenderEnginePlugin);univer.registerPlugin(UniverFormulaEnginePlugin);univer.registerPlugin(UniverUIPlugin, {container: 'excelContent',});univer.registerPlugin(UniverDocsPlugin);univer.registerPlugin(UniverDocsUIPlugin);univer.registerPlugin(UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUIPlugin);univer.registerPlugin(UniverSheetsFormulaPlugin);//必须指定iduniver.createUnit(UniverInstanceType.UNIVER_SHEET, {id: 'univer-1',sheets: {'sheet-01': {id: 'sheet-01',name: 'sheet1',cellData: {},},},});const univerAPI = FUniver.newAPI(univer)const ws = univerAPI.createSocket('ws://localhost:8089');ws.open$.subscribe(() => {console.log('websocket opened');// ws.send('hello')});ws.message$.subscribe((message) => {const data = message.data;let result = '';if (data instanceof Blob) {// Create a FileReader to read the Blob data  const reader = new FileReader();// Define the onload event handler  reader.onload = (e) => {// The result property contains the data as a typed array or string  // Here we assume the data is a UTF-8 encoded string  const resultData = e.target?.resultif (typeof resultData == 'string') {result = resultData;console.log(result);console.log('websocket message', result);const content = JSON.parse(result);//JSON.parse(message.data);console.log('content', content);const { command, options } = content;const { id, params } = command;console.log(params, 'params--------');// 接受到协同数据,本地落盘univerAPI.executeCommand(id, params, options);}};// Read the Blob data as a text string  reader.readAsText(data, 'utf-8');} else if (typeof data === 'string') {result = data;//console.log('websocket message', JSON.parse(message.data));console.log('websocket message', result);const content = JSON.parse(result);//JSON.parse(message.data);console.log('content', content);const { command, options } = content;const { id, params } = command;console.log(params, 'params--------');// 接受到协同数据,本地落盘univerAPI.executeCommand(id, params, options);}});ws.close$.subscribe(() => {console.log('websocket closed');});ws.error$.subscribe((error) => {console.log('websocket error', error);});univerAPI.onCommandExecuted((command, options) => {// 仅同步本地 mutationif (command.type !== 2 ||options?.fromCollab ||options?.onlyLocal ||command.id === 'doc.mutation.rich-text-editing') {return;}const commandInfo = JSON.stringify({command,options: { fromCollab: true },});console.log(commandInfo, 'commandInfo');ws.send(commandInfo);});
}
</script><style scoped></style>

在这里插入图片描述

导入导出禁止编辑

在这里插入图片描述
IWorksheetData
IWorkBookData
ICellData
导入导出
导入导出
导入的例子
导入导出

创建vue+univer项目

pnpm create vite --registry=http://registry.npm.taobao.org
pnpm add @univerjs/core @univerjs/design @univerjs/docs @univerjs/docs-ui @univerjs/engine-formula @univerjs/engine-render @univerjs/sheets @univerjs/sheets-formula @univerjs/sheets-ui @univerjs/ui --registry=http://registry.npm.taobao.org
pnpm add @univerjs/facade --registry=http://registry.npm.taobao.org
pnpm add @univerjs-pro/facade --registry=http://registry.npm.taobao.org

App.vue

<template><div><button @click="importExcel">加载数据</button><button @click="updateData">更新数据</button><button @click="closeOrOpenEditor">禁止或者开启编辑</button><button @click="saveData">保存数据</button></div><div ref="excelContent" style="width: 100%;height: 900px;"></div>
</template><script setup lang="ts">import "@univerjs/design/lib/index.css";
import "@univerjs/ui/lib/index.css";
import "@univerjs/docs-ui/lib/index.css";
import "@univerjs/sheets-ui/lib/index.css";
import "@univerjs/sheets-formula/lib/index.css";import {onMounted, ref} from 'vue'
import {LocaleType, Tools, Univer, UniverInstanceType, IWorkbookData, BooleanNumber} from "@univerjs/core";
import {defaultTheme} from "@univerjs/design";import {UniverFormulaEnginePlugin} from "@univerjs/engine-formula";
import {UniverRenderEnginePlugin} from "@univerjs/engine-render";import {UniverUIPlugin} from "@univerjs/ui";import {UniverDocsPlugin} from "@univerjs/docs";
import {UniverDocsUIPlugin} from "@univerjs/docs-ui";import {UniverSheetsPlugin} from "@univerjs/sheets";
import {UniverSheetsFormulaPlugin} from "@univerjs/sheets-formula";
import {UniverSheetsUIPlugin} from "@univerjs/sheets-ui";import DesignZhCN from '@univerjs/design/locale/zh-CN';
import UIZhCN from '@univerjs/ui/locale/zh-CN';
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN';
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN';
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN';
import SheetsFormulaZhCN from '@univerjs/sheets-formula/locale/zh-CN';
import {FUniver} from "@univerjs-pro/facade";const excelContent = ref<HTMLElement | null>(null)onMounted(() => {initSheet()
})let canEditor = true;
let univerAPI: FUniver | null = null;
let univer: Univer | null = null;
const initSheet = () => {univer = new Univer({theme: defaultTheme,locale: LocaleType.ZH_CN,locales: {[LocaleType.ZH_CN]: Tools.deepMerge(SheetsZhCN,DocsUIZhCN,SheetsUIZhCN,SheetsFormulaZhCN,UIZhCN,DesignZhCN,),},});univer.registerPlugin(UniverRenderEnginePlugin);univer.registerPlugin(UniverFormulaEnginePlugin);univer.registerPlugin(UniverUIPlugin, {container: excelContent.value!,});univer.registerPlugin(UniverDocsPlugin);univer.registerPlugin(UniverDocsUIPlugin);univer.registerPlugin(UniverSheetsPlugin);univer.registerPlugin(UniverSheetsUIPlugin);univer.registerPlugin(UniverSheetsFormulaPlugin);
}
const importExcel = () => {const workbook: IWorkbookData = {id: '007',//唯一idname: '部门人数统计',appVersion: '1.0.0',locale: LocaleType.ZH_CN,styles: {},sheetOrder: ['sheet1', 'sheet2'],sheets: {sheet1: {id: 'sheet1',name: '工作表 1',tabColor: '#FF0000',hidden: BooleanNumber.FALSE,freeze: {xSplit: 1, ySplit: 1, startRow: 1, startColumn: 1},rowCount: 1000,columnCount: 26,defaultColumnWidth: 100,defaultRowHeight: 25,mergeData: [],cellData: {// 第一行0: {//t表示类型 布尔、字符串和数字 https://univer.ai/typedoc/@univerjs/core/enumerations/CellValueType// 第一列0: {v: 'A1'},// 第二列1: {v: 'B1'},},// 第二行1: {// 第一列0: {v: 'A2'},// 第二列1: {v: 'B2'},},},rowData: [],columnData: [],rowHeader: {width: 40},columnHeader: {height: 20},showGridlines: BooleanNumber.TRUE,rightToLeft: BooleanNumber.FALSE},sheet2: {}}};if (univer != null) {console.log('univer!=null')if (univerAPI == null) {//模拟服务端获取数据univer.createUnit(UniverInstanceType.UNIVER_SHEET, workbook);univerAPI = FUniver.newAPI(univer);}} else {console.log('univer==null')}
}const updateData = () => {if (univerAPI != null) {const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet();// A1 设置数字 100const range = sheet?.getRange(0, 0, 1, 1);range?.setValue(100);}
}const closeOrOpenEditor = () => {canEditor = !canEditor;if (univerAPI != null) {const workBook = univerAPI.getActiveWorkbook();workBook?.setEditable(canEditor);}
}const saveData = () => {if (univerAPI != null) {const savedExcel = univerAPI.getActiveWorkbook()?.save();if (savedExcel != null) {console.log(savedExcel)}}else{console.log('数据为空')}
}
</script><style scoped>
</style>

在这里插入图片描述
配置单元格边框颜色

cellData: {// 第一行0: {//t表示类型 布尔、字符串和数字 https://univer.ai/typedoc/@univerjs/core/enumerations/CellValueType// 第一列0: {v: 'A1',},// 第二列1: {v: 'B1'},},// 第二行1: {// 第一列0: {v: 'A2'},// 第二列1: {v: 'B2',//边框s: {bd: {// 上边框t: {s: 7, // 边框样式cl: {  // 边框颜色rgb: '#ff0000'}},// 下边框b: {s: 7, // 边框样式cl: {  // 边框颜色rgb: '#ff0000'}},// 左边框l: {s: 7, // 边框样式cl: {  // 边框颜色rgb: '#ff0000'}},// 右边框r: {s: 7, // 边框样式cl: {  // 边框颜色rgb: '#ff0000'}},}}},},
},

在这里插入图片描述

高亮显示

pnpm add @univerjs/sheets-crosshair-highlight --registry=http://registry.npm.taobao.org

参考

https://univer.ai/zh-CN/guides/sheet/introduction
https://blog.csdn.net/m0_73884922/article/details/139971295
https://github.com/dream-num/usip-example/tree/main
https://github.com/dream-num/univer-pro-sheet-start-kit
https://github.com/dream-num/univer-sheet-start-kit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无线费控智能水表:智能生活的守护者

在当今智能化日益普及的时代&#xff0c;无线费控智能水表作为一项重要的技术创新&#xff0c;正在逐步改变我们的生活方式。它不仅能够实现远程抄表&#xff0c;自动计费&#xff0c;还能有效监控用水情况&#xff0c;促进水资源的合理利用&#xff0c;是现代城市智慧化管理不…

如何在 cPanel 中使用 PHP-FPM

PHP性能一直是影响网站托管的一个重要问题。PHP是当前网络上使用最广泛的服务器编程语言&#xff0c;远远领先于其他语言。最受欢迎的内容管理系统和电子商务应用程序&#xff0c;如WordPress、Joomla、Drupal、Magento等&#xff0c;都是用PHP编写的。 PHP-FPM加速了在繁忙服务…

24/10/12 算法笔记 NiN

LeNet、AlexNet和VGG都有一个共同的设计模式&#xff1a;通过一系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者&#xff0c;可以想象在这个过程的早期使用全连…

用java来编写web界面

一、ssm框架整体目录架构 二、编写后端代码 1、编写实体层代码 实体层代码就是你的对象 entity package com.cv.entity;public class Apple {private Integer id;private String name;private Integer quantity;private Integer price;private Integer categoryId;public…

C++:STL:vector类常用函数介绍(附加部分重要函数模拟实现)

cplusplus.com/reference/vector/vector/https://cplusplus.com/reference/vector/vector/ vector在实际中非常的重要&#xff0c;在实际中我们熟悉常见的接口就可以&#xff0c;有了string的基础&#xff0c;vector其实大体使用方法上二者是类似的&#xff1a; 这里我们先给…

ScriptableObject基本使用

使用方法 自定义类继承ScriptableObject 可以在类内部增加数据或者数据类&#xff0c;一般用于配置 注意事项 给继承ScriptableObject的类增加CreateAssetMenu特性。 CreateAssetMenu一般默认三个参数 第一个参数是父目录 第二个参数是父目录的子选项 第三个参数是可以…

多态(二)

1.多态的原理 虚函数表 class Base { public:virtual void Func1(){cout << "Func1()" << endl;} private:int _b 1; };b对象是8bytes&#xff0c;除了_b成员&#xff0c;还多一个__vfptr放在对象的前面(注意有些 平台可能会放到对象的最后面&#xf…

微信小程序启动不起来,报错凡是以~/包名/*.js路径的文件,都找不到,试过网上一切方法,最终居然这么解决的,【避坑】命运的齿轮开始转动

app.json "resolveAlias": {"~/*": "/*"},文件代码也没有问题&#xff0c;网上的方法试过来了&#xff0c;大模型AI也问过遍&#xff0c;熬夜到凌晨2点半&#xff0c;最不可思议的是居然是因为微信开发者工具版本的问题&#xff0c;我真的是笑死…

量化之一:均值回归策略

文章目录 均值回归策略理论基础数学公式 关键指标简单移动平均线&#xff08;SMA&#xff09;标准差Z-Score 交易信号实际应用优缺点分析优点缺点 结论 实践backtrader参数&#xff1a;正常情况&#xff1a;异常情况&#xff1a; 均值回归策略 均值回归&#xff08;Mean Rever…

JAVA-数据结构-排序

1.直接插入排序 1.原理&#xff1a;和玩扑克牌一样&#xff0c;从左边第二个牌开始&#xff0c;选中这个&#xff0c;和前面的所有牌比较&#xff0c;插在合适的位置 public static void insertsort(int[] arr){//直接插入排序for (int i 1; i < arr.length; i) {//此循环…

STM32 GPIO

GPIO&#xff08;通用输入输出口&#xff0c;General Purpose Input Output&#xff09;接口的功能是让嵌入式处理器能够通过软件灵活地读出或控制单个物理引脚上的高、低电平&#xff0c;实现内核和外部系统之间的信息交换。 GPIO是嵌入式处理器使用最多的外设&#xff0c;能够…

甲虫身体图像分割系统源码&数据集分享

甲虫身体图像分割系统源码&#xff06;数据集分享 [yolov8-seg-EfficientRepBiPAN&#xff06;yolov8-seg-C2f-FocusedLinearAttention等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challen…

毕设开源 大数据电影数据分析与可视化系统(源码+论文)

文章目录 0 前言1 项目运行效果2 设计概要3 最后 0 前言 &#x1f525;这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师…

简单粗暴理解GNN、GCN、GAT

GNN 思想&#xff1a;近朱者赤近墨者黑 GNN的流程&#xff1a; 聚合&#xff08;把邻居的信息贴到自己身上来&#xff0c;作为它自己特征的补足&#xff09;更新循环&#xff08;为什么要多次&#xff1f;看以下例子&#xff09; GNN能干嘛&#xff1f; 1.结点分类&#xf…

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

【网络协议】TCP协议常用机制——延迟应答、捎带应答、面向字节流、异常处理,保姆级详解,建议收藏

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 前几篇文章&#xff0c;博主带大家梳理了一下TCP协议的几个核心机制&#xff0c;比如保证可靠性的 确认应答、超时重传 机制&#xff0c;和提高传输效率的 滑动窗口及其相关优化机…

Qt实现Halcon窗口显示当前图片坐标

一、前言 Halcon加载图片的窗口&#xff0c;不仅能放大和缩小图片&#xff0c;还可以按住Ctrl键显示鼠标下的灰度值&#xff0c;这种方式很方便我们分析缺陷的灰度和对比度。 二、实现方式 ① 创建显示坐标和灰度的widget窗口 下图的是widget部件&#xff0c;使用了4个label控…

常说的风险评估,那么「基于风险的测试 (RBT)」如何测试?

基于风险的测试 &#xff08;RBT&#xff09; 是一种测试方法&#xff0c;它根据风险的概率和影响确定测试活动的优先级。它涉及在潜在问题发生之前识别它们&#xff0c;并将资源分配给风险最高的测试区域。 在 RBT 中&#xff0c;“风险”是指缺陷的可能性及其对系统运行或业…

DS线性表之单链表的讲解和实现(2)

文章目录 前言一、链表的概念二、链表的分类三、链表的结构四、前置知识准备五、单链表的模拟实现定义头节点初始化单链表销毁单链表打印单链表申请节点头插数据尾插数据头删数据尾删数据查询数据在pos位置之后插入数据删除pos位置之后的数据 总结 前言 本篇的单链表完全来说是…

架设传奇SF时提示此服务器满员,GEE引擎点开始游戏弹出服务器满员的解决方法

昨天一个朋友在架设GEE的传奇服务端时遇到一个奇怪的问题&#xff0c;就是在服务器外网架设时&#xff0c;建好角色点开始游戏提示此服务器满员&#xff0c;这个问题一般比较少见&#xff0c;而且出现的话一般都是GEE引擎的版本。 他折腾了半天&#xff0c;一直没进游戏&#x…