快速入门
html
<!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,
} = window
var 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
bash -c "$(curl -fsSL https://get.univer.ai)"
打开链接获取token,后续的安装就开始了
访问8000
bash
curl http://127.0.0.1:8000
如果机器停止了,重启之后可以运行
docker compose up
启动
页面部署
说明服务启动起来了,引入js库尝试,发现报错
html
<!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
} = window
var 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方式开发
bash
pnpm init
pnpm create vite --registry=http://registry.npm.taobao.org
bash
pnpm install --registry=http://registry.npm.taobao.org
pnpm run dev
安装依赖包
bash
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
修改App.vue
html
<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>
启动项目查看效果
协同编辑
bash
pnpm add @univerjs-pro/collaboration @univerjs-pro/collaboration-client --registry=http://registry.npm.taobao.org
修改App.vue
html
<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>
一直离线状态,没搞清楚原因
把官方的例子跑起来了,说明后端是没有问题的
代码如下
html
<!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/docker
const universerEndpoint = '192.168.56.10:8000';
// 协同插件从 URL 中获取 unit 参数,如果没有 unit 参数,则创建一个新的 unit
const 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协同
bash
pnpm init
pnpm add ws --registry=http://registry.npm.taobao.org
修改package.json
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
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启动起来
bash
pnpm run dev
前端参考vue3搭建起来,然后修改App.vue
html
<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);
//必须指定id
univer.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?.result
if (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) => {
// 仅同步本地 mutation
if (
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项目
bash
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
html
<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',//唯一id
name: '部门人数统计',
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 设置数字 100
const 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>
配置单元格边框颜色
js
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'
}
},
}
}
},
},
},
高亮显示
bash
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