简体   繁体   中英

Add SCEditor in Blazor WASM and a strange behavior

I want to use SCEditor in my blazor page.

For example I create a new blazor WASM project and I did these steps:

  1. According to documentation I add this codes and references to index.html :

https://cdn.jsdelivr.net/npm/sceditor@3/minified/themes/default.min.css https://cdn.jsdelivr.net/npm/sceditor@3/minified/sceditor.min.js https://cdn.jsdelivr.net/npm/sceditor@3/minified/formats/bbcode.min.js

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'
        });
    }
  1. Add a textarea in counter page:

     <textarea id="myTextArea" style="width:100%; height:200px;"></textarea>
  2. add follow code to code section of counter page:

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

Now I run the project and I see this editor:

在此处输入图像描述

then I click on fetch data menu and I see this:

在此处输入图像描述

Surprisingly, editor has shown in fetch data page. if I click on counter page again I see this:

在此处输入图像描述

There are 2 Editors OO. and if I click on this menus then editors are increasing...

How can I solve this problem?

Thanks


Edit 1)

I changed the code this way:

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

the editor is shown once in counter page and fetch data page. Again I don't have any textarea in fetch data page.

在此处输入图像描述

在此处输入图像描述

Blazor documentation warns :

Only mutate the Document Object Model (DOM) with JavaScript (JS) when the object doesn't interact with Blazor. Blazor maintains representations of the DOM and interacts directly with DOM objects. If an element rendered by Blazor is modified externally using JS directly or via JS Interop, the DOM may no longer match Blazor's internal representation, which can result in undefined behavior. Undefined behavior may merely interfere with the presentation of elements or their functions but may also introduce security risks to the app or server.

This guidance not only applies to your own JS interop code but also to any JS libraries that the app uses, including anything provided by a third-party framework, such as Bootstrap JS and jQuery .

SCEditor is exactly one of those DOM-mutating libraries, and the effects of failure to observe that guidance you can see for yourself.

Blazor does provide some interoperability with external DOM mutation in the form of element references . The documentation again warns:

Only use an element reference to mutate the contents of an empty element that doesn't interact with Blazor. This scenario is useful when a third-party API supplies content to the element. Because Blazor doesn't interact with the element, there's no possibility of a conflict between Blazor's representation of the element and the Document Object Model (DOM).

Heeding that warning, you should probably write something like below (not tested). In the component file ( .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);
    }
}

}

And in 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'
    });
}

If the SCEditor library is sufficiently well-behaved, it should only modify the DOM tree at most at the level of the parent of the textarea node you give it. You may think it would be enough to place a <textarea> in your component markup and capture a reference to that, but it may happen that SCEditor adds siblings to that node, which may keep messing up rendering. For that reason, it is safer to put everything in a wrapper element, which can act as a sandbox in which SCEditor has free rein.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM