Blazor作为一个新兴的交互式 Web UI 的框架,有其自身的优缺点,如果现有的 JavaScript 组件能移植到 Blazor,无疑让 Blazor 如虎添翼,本文就介绍一下自己在开发 BulmaRazor 组件库的时,封装现有的 JavaScript 组件的方法,文中以 TuiEditor 为例。
开始首先找到现有 TuiEditor 的主页或者文档,这一步很简单,我们找到官网 https://ui.toast.com/tui-editor/ ,分析一下组件的使用方法,一般都是有样式文件,有 JavaScript 文件,有一个 options 对象来初始化一个主对象,主对象上有方法和事件,大概就是这些了,我们先下载所需的文件,然后一步一步处理。
样式部分该组件需要两个样式 codemirror.min.css 和 toastui-editor.min.css ,由于一个组件库不只这一个组件,为了引用方便,我们需要使用 BuildBundlerMinifier 合并文件,不知道 BuildBundlerMinifier 的同学网上查一下。
在网站的根目录需要有 BuildBundlerMinifier 所需的配置文件 bundleconfig.json,对应的配置如下 : { "outputFileName": "wwwroot/bulmarazor.min.css", "inputFiles": [ "wwwroot/css/tuieditor/codemirror.min.css", "wwwroot/css/tuieditor/toastui-editor.min.css" ] },
项目中很可能还有其他的样式文件,一起合并就好了,引用的时候我们只需要一个样式文件,这里就是 bulmarazor.min.css。
脚本部分tuieditor 的 JavaScript 文件只有一个,当然一般 JavaScript 组件的脚本文件都是一个,如果是普通的 web 开发的话直接引入就可以了,但是在 Blazor 中有些麻烦,需要使用 JavaScript 互操作,互操作是指 C# 代码可调用到 JavaScript 代码,而 JavaScript 代码也可调用到 C# 代码。
C# 调用 JavaScript 代码有两种方法,一种是使用 IJSRuntime 调用挂载到 window 对象上的方法,另一种是使用模块隔离的方式调用,这里我们需要模块隔离,因为有以下优点:
导入的 JavaScript 不再污染全局命名空间。
库和组件的使用者不需要引用相关的 JavaScript。
关于 JavaScript 模块,可以参考这里 ,使用 JavaScript 模块依赖于 import 和 export,而一般的 JavaScript 类库并不支持,所以我们需要些一些导出的代码,文件结构如下:
我们忽视红色标注,先来看一下 toastui-editor-export.js 这个文件: export function initEditor(options) { options.el = document.getElementById(options.elid); let editor = new toastui.Editor.factory(options); return editor; }
toastui-editor-all.min.JavaScript 这个文件就是 JavaScript 组件文件,我们不用去改它,也不应该去改它,因为后续升级了我们可以直接覆盖的,toastui-editor-export.js 就是我们专门写的一个导出类库中所需功能的导出文件。为了引用方便我们还是需要合并一下,就是图片示现的那样,合并配置如下:
{ "outputFileName": "wwwroot/js/tuieditor.min.js", "inputFiles": [ "wwwroot/jsplugin/tuieditor/toastui-editor-all.min.js", "wwwroot/jsplugin/tuieditor/toastui-editor-export.js" ] }现在我们使用隔离的方式引用 wwwroot/js/tuieditor.min.js 就可以了。当我们新建一个Razor组件项目的时候,会带有调用的例子,我们比猫画虎搞定:
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; namespace BulmaRazor.Components { public class BulmaRazorJsInterop : IAsyncDisposable { private readonly Lazy<Task<IJSObjectReference>> tuiEditorModuleTask; public BulmaRazorJsInterop(IJSRuntime jsRuntime) { tuiEditorModuleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>( "import", "./_content/BulmaRazor/js/tuieditor.min.js").AsTask()); } public async ValueTask<IJSObjectReference> TuiEditorInit(TuiEditorOptions options) { var module = await tuiEditorModuleTask.Value; return await module.InvokeAsync<IJSObjectReference>("initEditor", options.ToParams()); } public async ValueTask DisposeAsync() { if (tuiEditorModuleTask.IsValueCreated) { var module = await tuiEditorModuleTask.Value; await module.DisposeAsync(); } } } } Blazor 组件部分组件文件是 TuiEditor.razor,UI代码是非常简单的,就是一个带有 id 属性的 div 容器,id 很重要,是我们互操作的基础,这里我们使用GUID生成唯一的id。
我们需要在 blazor 组件呈现之后调用 JavaScript 代码来初始化我们的 JavaScript 组件,调用 JavaScript 代码之后返回了js 对象的引用editor,注意editor和上述 var module = await tuiEditorModuleTask.Value; 中的 module 是一样的,都是 JavaScript 对象引用。大致的代码如下: