Skip to content

Commit b74721d

Browse files
feat(UniverSheet): add UniverSheet component (#343)
* feat: 增加 BootstrapBlazor.UniverSheet 扩展包 * refactor: 更改文件扩展名 * refactor: 更新脚本 * feat: 增加插件支持 * refactor: 增加 Name 参数 * feat: 增加 UniverSheetData 类用于数据通讯 * feat: 交互测试 * refactor: 更新 OnPostDataAsync 参数 * refactor: 更新脚本 * refactor: 增加捆绑样式 * refactor: 更改方法名 * refactor: 支持多数据服务 * refactor: 删除冗余代码 * refactor: 增加返回值 * refactor: 代码格式化 * refactor: 增加提示信息 * refactor: 移除数据服务相关代码 * refactor: 增加 univer 脚本 * refactor: 拆分数据服务 * refactor: 增加数据检查逻辑 * refactor: 规范方法名 * feat: 增加 Dispose 方法 * refactor: 增加 this 关键字 * feat: 增加 OnReadyAsync 回调支持 * refactor: 调整代码 * feat: 增加默认插件 * refactor: 精简代码 * feat: 增加默认插件逻辑 * refactor: 复用 isFunction 函数 * refactor: 增加 dispose 方法 --------- Co-authored-by: zhaijunlei <276318515@qq.com>
1 parent 64ab404 commit b74721d

23 files changed

Lines changed: 1492 additions & 0 deletions

BootstrapBlazor.Extensions.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.JuHeIpLocat
176176
EndProject
177177
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Html2Image", "src\components\BootstrapBlazor.Html2Image\BootstrapBlazor.Html2Image.csproj", "{F184D96E-7855-4E3B-B447-D09DBC1C91C6}"
178178
EndProject
179+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.UniverSheet", "src\components\BootstrapBlazor.UniverSheet\BootstrapBlazor.UniverSheet.csproj", "{E30AAB64-BF28-4960-89C1-1F521025F531}"
180+
EndProject
179181
Global
180182
GlobalSection(SolutionConfigurationPlatforms) = preSolution
181183
Debug|Any CPU = Debug|Any CPU
@@ -474,6 +476,10 @@ Global
474476
{F184D96E-7855-4E3B-B447-D09DBC1C91C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
475477
{F184D96E-7855-4E3B-B447-D09DBC1C91C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
476478
{F184D96E-7855-4E3B-B447-D09DBC1C91C6}.Release|Any CPU.Build.0 = Release|Any CPU
479+
{E30AAB64-BF28-4960-89C1-1F521025F531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
480+
{E30AAB64-BF28-4960-89C1-1F521025F531}.Debug|Any CPU.Build.0 = Debug|Any CPU
481+
{E30AAB64-BF28-4960-89C1-1F521025F531}.Release|Any CPU.ActiveCfg = Release|Any CPU
482+
{E30AAB64-BF28-4960-89C1-1F521025F531}.Release|Any CPU.Build.0 = Release|Any CPU
477483
EndGlobalSection
478484
GlobalSection(SolutionProperties) = preSolution
479485
HideSolutionNode = FALSE
@@ -556,6 +562,7 @@ Global
556562
{8A46FEDF-FD76-48AB-9BB2-47254C7623A4} = {FF1089BE-C704-4374-B629-C57C08E1798F}
557563
{C882891F-4A6A-C9BE-AC96-227764A4A46A} = {FF1089BE-C704-4374-B629-C57C08E1798F}
558564
{F184D96E-7855-4E3B-B447-D09DBC1C91C6} = {FF1089BE-C704-4374-B629-C57C08E1798F}
565+
{E30AAB64-BF28-4960-89C1-1F521025F531} = {FF1089BE-C704-4374-B629-C57C08E1798F}
559566
EndGlobalSection
560567
GlobalSection(ExtensibilityGlobals) = postSolution
561568
SolutionGuid = {D5EB1960-6F30-4CE1-B375-EAE1F787D6FF}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
2+
3+
<PropertyGroup>
4+
<Version>9.0.0-beta01</Version>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Univer Sheet Excel</PackageTags>
9+
<Description>Bootstrap UI components extensions of Univer Sheet</Description>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Using Include="Microsoft.JSInterop" />
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@namespace BootstrapBlazor.Components
2+
@inherits BootstrapModuleComponentBase
3+
@attribute [JSModuleAutoLoader("./_content/BootstrapBlazor.UniverSheet/Components/UniverSheet.razor.js", JSObjectReference = true)]
4+
5+
<div @attributes="@AdditionalAttributes" class="@ClassString" id="@Id"></div>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
using Microsoft.AspNetCore.Components;
6+
7+
namespace BootstrapBlazor.Components;
8+
9+
/// <summary>
10+
/// UniverSheet 组件
11+
/// </summary>
12+
public partial class UniverSheet
13+
{
14+
/// <summary>
15+
/// 获得/设置 插件集合 默认 null 未设置
16+
/// </summary>
17+
[Parameter]
18+
public Dictionary<string, string>? Plugins { get; set; }
19+
20+
/// <summary>
21+
/// 获得/设置 Name 默认 null 未设置
22+
/// </summary>
23+
[Parameter]
24+
public string? Name { get; set; }
25+
26+
/// <summary>
27+
/// 获得/设置 主题颜色 默认 null 未设置
28+
/// </summary>
29+
[Parameter]
30+
public string? Theme { get; set; }
31+
32+
/// <summary>
33+
/// 获得/设置 语言 默认 null 未设置
34+
/// </summary>
35+
[Parameter]
36+
public string? Lang { get; set; }
37+
38+
/// <summary>
39+
/// 获得/设置 需要传递的数据
40+
/// </summary>
41+
[Parameter]
42+
public UniverSheetData? Data { get; set; }
43+
44+
/// <summary>
45+
/// 获得/设置 Frame 加载页面传递过来的数据
46+
/// </summary>
47+
[Parameter]
48+
public Func<UniverSheetData?, Task<UniverSheetData?>>? OnPostDataAsync { get; set; }
49+
50+
private string? ClassString => CssBuilder.Default("bb-univer-sheet")
51+
.AddClassFromAttributes(AdditionalAttributes)
52+
.Build();
53+
54+
private UniverSheetData? _lastData;
55+
56+
/// <summary>
57+
/// <inheritdoc/>
58+
/// </summary>
59+
/// <param name="firstRender"></param>
60+
protected override async Task OnAfterRenderAsync(bool firstRender)
61+
{
62+
await base.OnAfterRenderAsync(firstRender);
63+
64+
if (_lastData != Data)
65+
{
66+
_lastData = Data;
67+
await PushDataAsync(Data);
68+
}
69+
}
70+
71+
/// <summary>
72+
/// <inheritdoc/>
73+
/// </summary>
74+
/// <returns></returns>
75+
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new { SheetName = Name, Theme, Lang, Plugins });
76+
77+
/// <summary>
78+
/// 推送数据方法
79+
/// </summary>
80+
/// <param name="data"></param>
81+
/// <returns></returns>
82+
public Task PushDataAsync(UniverSheetData? data) => InvokeVoidAsync("execute", Id, data);
83+
84+
/// <summary>
85+
/// 由 JavaScript 调用
86+
/// </summary>
87+
/// <param name="data"></param>
88+
/// <returns></returns>
89+
[JSInvokable]
90+
public async Task<UniverSheetData?> TriggerPostData(UniverSheetData data) => OnPostDataAsync == null
91+
? null
92+
: await OnPostDataAsync(data);
93+
94+
/// <summary>
95+
/// 获得/设置 页面加载完毕后回调方法
96+
/// </summary>
97+
[Parameter]
98+
public Func<Task>? OnReadyAsync { get; set; }
99+
100+
/// <summary>
101+
/// 由 JavaScript 调用
102+
/// </summary>
103+
/// <returns></returns>
104+
[JSInvokable]
105+
public async Task TriggerReadyAsync()
106+
{
107+
if (OnReadyAsync != null)
108+
{
109+
await OnReadyAsync();
110+
}
111+
}
112+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Data from '../../BootstrapBlazor/modules/data.js'
2+
import { isFunction } from '../../BootstrapBlazor/modules/utility.js'
3+
import { createUniverSheetAsync } from '../univer.js'
4+
5+
6+
export async function init(id, invoke, options) {
7+
const el = document.getElementById(id);
8+
if (el === null) {
9+
return;
10+
}
11+
12+
const univerSheet = {
13+
el,
14+
invoke,
15+
options
16+
};
17+
await createUniverSheetAsync(univerSheet);
18+
Data.set(id, univerSheet);
19+
20+
invoke.invokeMethodAsync('TriggerReadyAsync');
21+
}
22+
23+
export function execute(id, data) {
24+
const univerSheet = Data.get(id);
25+
26+
univerSheet.pushData(data);
27+
}
28+
29+
export function dispose(id) {
30+
const univerSheet = Data.get(id);
31+
Data.remove(id);
32+
33+
if (isFunction(univerSheet.dispose)) {
34+
univerSheet.dispose();
35+
}
36+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
namespace BootstrapBlazor.Components;
6+
7+
/// <summary>
8+
/// UniverSheetData 组件数据类
9+
/// </summary>
10+
public class UniverSheetData
11+
{
12+
/// <summary>
13+
/// 获得/设置 消息名称 默认 null 未设置
14+
/// </summary>
15+
public string? MessageName { get; set; }
16+
17+
/// <summary>
18+
/// 获得/设置 命令名称 默认 null 未设置
19+
/// </summary>
20+
public string? CommandName { get; set; }
21+
22+
/// <summary>
23+
/// 获得/设置 数据 默认 null 未设置
24+
/// </summary>
25+
public object? Data { get; set; }
26+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { isFunction } from '../BootstrapBlazor/modules/utility.js'
2+
3+
export default class DataService {
4+
static name = 'DataService';
5+
6+
registerUniverSheet(sheet) {
7+
sheet.pushData = data => {
8+
this._checkReceiveDataCallback();
9+
this._callback(data);
10+
};
11+
this._sheet = sheet;
12+
}
13+
14+
registerReceiveDataCallback(callback) {
15+
this._callback = callback;
16+
}
17+
18+
getUniverSheet() {
19+
this._checkUniverSheet();
20+
return this._sheet;
21+
}
22+
23+
async getDataAsync(data) {
24+
this._checkUniverSheet();
25+
return await this._sheet.invoke.invokeMethodAsync('TriggerPostData', data);
26+
}
27+
28+
_checkUniverSheet() {
29+
if (this._sheet === void 0) {
30+
throw new Error('UniverSheet is not registered. Please call registerUniverSheet first');
31+
}
32+
}
33+
34+
_checkReceiveDataCallback() {
35+
if (isFunction(this._callback) === false) {
36+
throw new Error('Receive data callback is not registered. Please call registerReceiveDataCallback first');
37+
}
38+
}
39+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import DataService from './data-service.js'
2+
3+
const { Plugin, Injector, setDependencies } = UniverCore;
4+
5+
// 定义插件类
6+
export class DefaultPlugin extends Plugin {
7+
static pluginName = 'DefaultPlugin';
8+
9+
constructor(_injector) {
10+
super();
11+
12+
this._injector = _injector;
13+
}
14+
15+
onStarting() {
16+
this._injector.add([DataService.name, { useClass: DataService }])
17+
}
18+
19+
onReady() {
20+
this._dataService = this._injector.get(DataService.name);
21+
this._dataService.registerReceiveDataCallback(data => {
22+
this.receiveData(data);
23+
});
24+
}
25+
26+
onRendered() {
27+
28+
}
29+
30+
receiveData(data) {
31+
this._sheet ??= this._dataService.getUniverSheet();
32+
const sheetData = data.data;
33+
const { univerAPI } = this._sheet;
34+
const rows = sheetData.length;
35+
let cols = 1;
36+
if (rows > 0) {
37+
cols = sheetData[0].length;
38+
}
39+
const range = univerAPI.getActiveWorkbook().getActiveSheet().getRange(0, 0, rows, cols)
40+
const defaultData = sheetData.map(d => {
41+
return d.map(v => {
42+
return { v: v };
43+
});
44+
});
45+
range.setValues(defaultData);
46+
}
47+
}
48+
49+
// 设置依赖
50+
setDependencies(DefaultPlugin, [Injector]);
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { addScript, addLink } from '../BootstrapBlazor/modules/utility.js'
2+
import DataService from './data-service.js'
3+
4+
const loadAssets = async () => {
5+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/react.production.min.js');
6+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/react-dom.production.min.js');
7+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/rxjs.umd.min.js');
8+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.presets.umd.min.js');
9+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.preset-sheets-core.umd.min.js');
10+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.preset-sheets-drawing.umd.min.js');
11+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.sheets-zen-editor.umd.min.js');
12+
13+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.preset-sheets-core.locales.zh-CN.js');
14+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.preset-sheets-drawing.locales.zhCN.js');
15+
await addScript('./_content/BootstrapBlazor.UniverSheet/univer/js/univerjs.sheets-zen-editor.locales.zh-CN.js');
16+
17+
await addLink('./_content/BootstrapBlazor.UniverSheet/univer/css/univer-sheet.bundle.css');
18+
}
19+
20+
21+
export async function createUniverSheetAsync(sheet) {
22+
await loadAssets();
23+
24+
const { el } = sheet;
25+
const { LocaleType, merge } = UniverCore;
26+
const { createUniver } = UniverPresets;
27+
const { UniverSheetsCorePreset } = UniverPresetSheetsCore;
28+
const { UniverSheetsDrawingPreset } = UniverPresetSheetsDrawing;
29+
const { UniverSheetsZenEditorPlugin } = UniverSheetsZenEditor
30+
const { defaultTheme } = UniverDesign;
31+
const options = {
32+
theme: defaultTheme,
33+
locale: LocaleType.ZH_CN,
34+
locales: {
35+
[LocaleType.ZH_CN]: merge(
36+
{},
37+
UniverPresetSheetsCoreZhCN,
38+
UniverPresetSheetsDrawingZhCN,
39+
UniverSheetsZenEditorZhCN
40+
),
41+
},
42+
plugins: [
43+
UniverSheetsZenEditorPlugin
44+
]
45+
};
46+
const plugins = sheet.options.plugins ?? {
47+
DefaultPlugin: '_content/BootstrapBlazor.UniverSheet/plugin.js'
48+
};
49+
for (const name in plugins) {
50+
const module = await import(`../../../${plugins[name]}`);
51+
const plugin = module[name];
52+
options.plugins.push(plugin);
53+
}
54+
55+
const { univer, univerAPI } = createUniver({
56+
presets: [
57+
UniverSheetsCorePreset({
58+
container: el
59+
}),
60+
UniverSheetsDrawingPreset(),
61+
],
62+
...options
63+
});
64+
65+
univerAPI.createUniverSheet();
66+
sheet.univer = univer;
67+
sheet.univerAPI = univerAPI;
68+
sheet.dispose = () => {
69+
univer.dispose();
70+
}
71+
72+
const dataService = univer._injector.get(DataService.name);
73+
dataService.registerUniverSheet(sheet);
74+
}

0 commit comments

Comments
 (0)