日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

如何优雅的移植JavaScript组件到Blazor

發布時間:2023/12/4 javascript 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何优雅的移植JavaScript组件到Blazor 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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 對象引用。大致的代碼如下:

@inject BulmaRazorJsInterop JsInterop<div id="@Id"></div>@code {readonly string Id = "tuiEditor_" + Guid.NewGuid().ToString("N");IJSObjectReference editor;[Parameter]public TuiEditorOptions Options { get; set; }protected override void OnInitialized(){if (Options == null)Options = new TuiEditorOptions();Options.elid = Id;base.OnInitialized();}protected override async Task OnAfterRenderAsync(bool firstRender){await base.OnAfterRenderAsync(firstRender);editor = await JsInterop.TuiEditorInit(Options);} }

Options選項部分

TuiEditor 組件中有個參數 TuiEditorOptions ,是要對應 JavaScript 中的 options 參數的,我們需要自己定義一個,這里我們使用兩個類來使用,一個是針對 JavaScript 的 JsParams 類似字典的對象,一個是針對使用者的 TuiEditorOptions 。
JsParams 就是一個Dictionary<string,object>,為了方便,我們過濾了空值:

internal class JsParams:Dictionary<string,object>{public void AddNotNull(string key, object value){if (value != null){base.Add(key,value);}}}

TuiEditorOptions 類除了參數之外,包含一個 ToParams() 的方法把自己轉換成 JsParams:

public class TuiEditorOptions {internal string elid { get; set; }/// <summary>/// Editor's height style value. Height is applied as border-box ex) '300px', '100%', 'auto'/// </summary>public string Height { get; set; }/// <summary>/// 是否是查看器/// </summary>public bool? Viewer { get; set; }//...其他參數internal JsParams ToParams(){JsParams ps = new JsParams();var def = BulmaRazorOptions.DefaultOptions.TuiEditorOptions;ps.AddNotNull("elid", elid);ps.AddNotNull("viewer",Viewer);ps.AddNotNull("height", Height ?? def.Height);//...其他參數return ps;} }

有幾個原因使用 JsParams :

  • null值可以不傳遞,因為js的options一般都用默認值,減少傳輸;

  • 可以使用默認設置,如上有個BulmaRazorOptions.DefaultOptions.TuiEditorOptions;

  • 可以靈活的手動處理參數,上面例子沒有提現出來,不過組件寫多了肯定會遇到這種情況;

對象的方法

JavaScript 組件一般也會公開許多實例方法,比如獲得焦點,設置內容,獲取內容等等,在在前面我們一直保存了 JavaScript 組件實例的引用,也就是在 TuiEditor 中的 editor 對象,向公開哪些方法在 TuiEditor.razor 中添加就是了:

public void Focus(){editor?.InvokeVoidAsync("focus");}public ValueTask<string> GetMarkdown(){return editor?.InvokeAsync<string>("getMarkdown") ?? new ValueTask<string>("");}public void InsertText(string text){editor?.InvokeVoidAsync("insertText", text);}public ValueTask<bool> IsViewer(){return editor?.InvokeAsync<bool>("isViewer") ?? new ValueTask<bool>(false);}//...其他需要的方法

對象事件

JavaScript 組件對象有自己的事件,在 JavaScript 中直接設置 JavaScript 函數就可以了,但是并不能把 C# 方法或者委托傳遞給 js,這里就需要用到 JavaScript 調用C#方法了。
Blazor 框架中 JavaScript 只能調用靜態方法,而我們實際中是基于對象來寫邏輯的,所有我專門寫了一個類來處理js的調用,JSCallbackManager:

public static class JSCallbackManager{private static ConcurrentDictionary<string, Dictionary<string, Delegate>> eventHandlerDict = new();public static void AddEventHandler(string objId, string eventKey, Delegate @delegate){var eventHandlerList = eventHandlerDict.GetOrAdd(objId, (key) => new Dictionary<string, Delegate>());eventHandlerList[eventKey]= @delegate;}public static void DisposeObject(string objId){if (eventHandlerDict.Remove(objId, out Dictionary<string, Delegate> handlers)){handlers.Clear();}}[JSInvokable]public static object JSCallback(string objId, string eventKey){if (eventHandlerDict.TryGetValue(objId, out Dictionary<string, Delegate> handlers)){if (handlers.TryGetValue(eventKey, out Delegate d)){var obj = d.DynamicInvoke();return obj;}}return null;}}

我們使用一個嵌套的字典來保存了Blazor組件的回調委托,每一個組件對象都有一個唯一的Id,每一個組件類型都可以有不同名稱的 JavaScript 事件回調。
比如我們想訂閱 JavaScript 組件實例的 load 事件,我們需要改兩個地方,第一個是 toastui-editor-export.js 導出文件:

export function initEditor(options) {options.el = document.getElementById(options.elid);options.events = {load: function () {DotNet.invokeMethodAsync("BulmaRazor", "JSCallback", options.elid, "load");}}let editor = new toastui.Editor.factory(options);return editor; }

JavaScript 的事件還是需要用 js來做,然后在js方法內部調用 C# 方法。第二個是需要在 TuiEditor 中添加回調委托:

[Parameter]public EventCallback<TuiEditor> OnLoad { get; set; }protected override void OnInitialized(){if (Options == null)Options = new TuiEditorOptions();Options.elid = Id;//這里添加回調委托,并把js事件公開成了Blazor組件事件JSCallbackManager.AddEventHandler(Id, "load", new Func<Task>(() => OnLoad.InvokeAsync(this)));base.OnInitialized();}protected override ValueTask DisposeAsync(bool disposing){//移除對象的所有回調委托JSCallbackManager.DisposeObject(Id);return base.DisposeAsync(disposing);}

這樣我們就把 JavaScript 組件事件移植到了 Blazor 組件。

修整

經過上述不知,組件基本移植完了,但還不能很好的使用,第一,因為界面是 js在操作,所以我們應該禁用 Blazor組件的渲染:

protected override bool ShouldRender(){return false;}

在js的options中有個initialValue屬性,是初始化內容的,我們改成Blazor的形式,最好是可以綁定:

[Parameter]public EventCallback<TuiEditor> OnBlur { get; set; }protected override void OnInitialized(){if (Options == null)Options = new TuiEditorOptions();Options.InitialValue = _value;Options.elid = Id;//這里也是通過js事件觸發JSCallbackManager.AddEventHandler(Id, "blur", new Func<Task>(async () =>{await setValue();await OnBlur.InvokeAsync(this);}));base.OnInitialized();}private string _value;[Parameter]public string Value{get { return _value; }set{_value = value;SetMarkdown(value, true);}}[Parameter]public EventCallback<string> ValueChanged { get; set; }private async Task setValue(){_value = await GetMarkdown();await ValueChanged.InvokeAsync(_value);}public void SetMarkdown(string markdown, bool cursorToEnd = true){editor?.InvokeVoidAsync("setMarkdown", markdown, cursorToEnd);}

這樣我們就可以使用 Blazor 綁定語法了:

<TuiEditor @bind-Value="markdown"></TuiEditor> @code{private string markdown = "# Init Title"; }

效果如下:

在線效果點擊這里

源代碼

  • BulmaRazor官網

  • Gitee地址

  • Github地址

希望喜歡 Blazor 和 BulmaRazor 的朋友給個Star鼓勵一下!該項目從2021年的春節假期開始,一個人做真心的累和耗時,您的鼓勵是我堅持下去的最大動力!

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的如何优雅的移植JavaScript组件到Blazor的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。