1

我想在我的 Blazor 页面中使用SCEditor 。

例如,我创建了一个新的 Blazor WASM 项目,并执行了以下步骤:

  1. 根据文档,我将此代码和引用添加到index.html

    window.InitEditor = () => {
        var textarea = document.getElementById('myTextArea');
        sceditor.create(textarea, {
            format: 'bbcode',
            style: 'https://cdn.jsdelivr.net/npm/sceditor@3/minified/themes/content/default.min.css'
        });
    };
    
  2. textareacounter页面中添加:

    <textarea id="myTextArea" style="width:100%; height:200px;"></textarea>
    
  3. 将以下代码添加到页面的代码部分counter

    protected override Task OnAfterRenderAsync(bool firstRender)
    {
        JsRuntime.InvokeVoidAsync("InitEditor");
        return base.OnAfterRenderAsync(firstRender);
    }
    

现在我运行项目,我看到了这个编辑器:

在此处输入图像描述

然后我点击获取数据菜单,我看到了这个:

在此处输入图像描述

令人惊讶的是,编辑器已显示在获取数据页面中。如果我再次点击计数器页面,我会看到:

在此处输入图像描述

有 2 名编辑 OO。如果我点击这个菜单,那么编辑器正在增加......

我以这种方式更改了代码:

protected override Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
        JsRuntime.InvokeVoidAsync("InitEditor");
    return base.OnAfterRenderAsync(firstRender);
}

编辑器在counter页面和fetch data页面中显示一次。textarea同样,我没有任何fetch data页面。

在此处输入图像描述

在此处输入图像描述

我怎么解决这个问题?

4

1 回答 1

1

Blazor 文档警告

仅当对象不与 Blazor 交互时,才使用 JavaScript (JS) 改变文档对象模型 (DOM)。Blazor 维护 DOM 的表示并直接与 DOM 对象交互。如果直接使用 JS 或通过 JS Interop 在外部修改 Blazor 呈现的元素,则 DOM 可能不再匹配 Blazor 的内部表示,这可能导致未定义的行为。未定义的行为可能只会干扰元素或其功能的呈现,但也可能会给应用程序或服务器带来安全风险。

本指南不仅适用于您自己的 JS 互操作代码,还适用于应用程序使用的任何 JS 库,包括第三方框架提供的任何内容,例如Bootstrap JSjQuery

SCEditor 正是那些 DOM 变异库之一,不遵守该指导的后果您可以亲眼看到。(“安全风险”位相当荒谬:如果仅通过修改客户端代码就可以使您的应用程序变得不安全,那么一开始就不是很安全。但这是一个很好的建议。)

Blazor 确实以元素引用的形式提供了与外部 DOM 突变的一些互操作性。该文档再次警告:

仅使用元素引用来改变不与 Blazor 交互的空元素的内容。当第三方 API 向元素提供内容时,此方案很有用。因为 Blazor 不与元素交互,所以 Blazor 的元素表示与文档对象模型 (DOM) 之间不存在冲突的可能性。

注意该警告,您可能应该编写如下内容(未经测试)。在组件文件 ( .razor) 中:

<div @ref="sceditorContainer"></div>

@inject IJSRuntime js

@code {

private ElementReference sceditorContainer;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    await base.OnAfterRenderAsync(firstRender);
    if (firstRender)
    {
        await js.InvokeVoidAsync("initEditor", sceditorContainer);
    }
}

}

在 JavaScript 中:

function initEditor(container) {
    const textarea = document.createElement('textarea');
    container.appendChild(textarea);
    sceditor.create(textarea, {
        format: 'bbcode',
        style: 'https://cdn.jsdelivr.net/npm/sceditor@3/minified/themes/content/default.min.css'
    });
}

如果 SCEditor 库表现得足够好,它最多只能在你给它的 textarea 节点的父级级别修改 DOM 树。您可能认为<textarea>在组件标记中放置 a 并捕获对它的引用就足够了,但当它发生时,SCEditor 会向该节点添加兄弟节点,这可能会继续搞乱渲染。出于这个原因,将所有内容放在一个最初为空的包装元素中会更安全,它可以充当 SCEditor 可以自由控制的沙箱。

于 2022-01-11T12:14:02.477 回答