问题
I want to use TinyMCE in a Blazor server side app, but it shows up on page load for a second and then disappears. I blame it on StatehasChanged()
thus I have written an interop function that re-initializes TinyMCE and is called in the OnAfterRender()
of the page.
This is the JS interop function:
initTinyMce: function (tinyMceID) {
tinymce.init({
selector: 'textarea.tinyMce'
});
return "";
//var editor = tinyMCE.get(tinyMceID);
//if (editor && editor instanceof tinymce.Editor) {
// editor.init();
//}
}
In the OnAfterRender
I call it like so:
protected override void OnAfterRender() {
base.OnAfterRender();
string a = jsInterop.InitTinyMce("myTinyMce").Result;
}
But still it disappears a second after it shows itself. How to fix this problem?
回答1:
I wasn't able to get it to mimic this behaviour so maybe you were using a different version of tinyMce and Blazor. I'm using TinyMce 5.3.1 and .Net Core 3.1. I see you switched to using SyncFusion but maybe this answer will help anyone else who comes along here looking to try to do this in Blazor like I was yesterday.
I think the main thing is disposing of the element when you navigate away and re-initializing when it comes into view / focus / is loaded / etc...
Here's a component that I put together last night that should take care of all the pieces and make it bind-able like a regular <InputTextArea>
I'm new to Blazor and components. This is the second bind-able form control I've made. If anyone has any comments or suggestions on how this could be better please edit or let me know and I can update. Thanks!
In the JS block in _Host.html (i'm using a local version of TinyMCE)
<script src="/js/tinymce/tinymce.min.js"></script>
/Shared/Components/Textarea.razor
<textarea id="@Id" @bind-value="Value" @bind-value:event="onchange" />
/Shared/Components/Textarea.razor.cs:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
namespace Application.Shared.Components
{
public partial class Textarea : ComponentBase, IDisposable
{
[Inject] private IJSRuntime JSRuntime { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string Value { get; set; }
[Parameter] public EventCallback<string> ValueChanged { get; set; }
[Parameter] public string Id { get; set; } = null;
private DotNetObjectReference<Textarea> _elementRef;
[Parameter] public MenuModeEnum MenuMode { get; set; } = MenuModeEnum.standard;
protected string FieldClass => GivenEditContext?.FieldCssClass(FieldIdentifier) ?? string.Empty;
protected EditContext GivenEditContext { get; set; }
protected FieldIdentifier FieldIdentifier { get; set; }
protected string CurrentValue
{
get => Value;
set
{
var hasChanged = !EqualityComparer<string>.Default.Equals(value, Value);
if (!hasChanged) return;
_ = value;
Value = value;
_ = ValueChanged.InvokeAsync(value);
GivenEditContext?.NotifyFieldChanged(FieldIdentifier);
}
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
this.Id = Id ?? Guid.NewGuid().ToString();
_elementRef = DotNetObjectReference.Create(this);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeVoidAsync("TinyMce.init", Id, Enum.GetName(typeof(MenuModeEnum), MenuMode), _elementRef);
}
}
[JSInvokable("textArea_OnChange")]
public void Change(string value)
{
CurrentValue = value;
}
protected virtual void Dispose(bool disposing)
{
JSRuntime.InvokeVoidAsync("TinyMce.dispose", Id, _elementRef);
}
void IDisposable.Dispose()
{
Dispose(disposing: true);
}
internal void DismissInstance()
{
JSRuntime.InvokeVoidAsync("TinyMce.dispose", Id, _elementRef);
StateHasChanged();
}
}
}
/Shared/Components/Enums/MenuModeEnum.cs:
namespace Application.Shared.Components.Enums
{
public enum MenuModeEnum
{
standard,
minimal,
grouped,
bloated
}
}
/wwwroot/js/site.js:
if (!window.TinyMce) {
window.TinyMce = {};
}
window.TinyMce = {
params : {
standard: {
plugins: 'code codesample link image autolink lists media paste table table spellchecker',
toolbar1: 'undo redo | paste | removeformat styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | link image media codesample | table | code | spellchecker',
menubar: false,
branding: false,
toolbar_mode: 'floating'
},
minimal: {
toolbar1: 'bold italic underline',
menubar: false,
branding: false,
toolbar_mode: 'floating'
},
grouped: {
plugins: "emoticons hr image link lists charmap table",
toolbar: "formatgroup paragraphgroup insertgroup",
toolbar_groups: {
formatgroup: {
icon: 'format',
tooltip: 'Formatting',
items: 'bold italic underline strikethrough | forecolor backcolor | superscript subscript | removeformat'
},
paragraphgroup: {
icon: 'paragraph',
tooltip: 'Paragraph format',
items: 'h1 h2 h3 | bullist numlist | alignleft aligncenter alignright alignjustify | indent outdent'
},
insertgroup: {
icon: 'plus',
tooltip: 'Insert',
items: 'link image emoticons charmap hr'
}
},
menubar: false,
branding: false
},
bloated: {
plugins: 'code codesample link image autolink lists media paste table table spellchecker',
toolbar1: 'undo redo | styleselect | forecolor | bold italic underline strikethrough | link image media codesample | table | code | spellchecker',
toolbar2: 'h1 h2 h3 | bullist numlist | alignleft aligncenter alignright alignjustify | outdent indent | emoticons charmap hr',
menubar: false,
branding: false,
toolbar_mode: 'floating'
}
},
init: function (id, mode, dotnetHelper) {
var params = window.TinyMce.params[mode];
params.selector = '#' + id;
params.setup = function (editor) {
editor.on('change', function (e) {
console.log($('#' + id).val());
$('#' + id).val(editor.getContent());
$('#' + id).change();
console.log($('#' + id).val());
dotnetHelper.invokeMethodAsync("textArea_OnChange", $('#' + id).val());
});
}
tinymce.init(params);
},
dispose: function (id, dotnetHelper) {
tinymce.remove('#' + id);
}
};
Usage:
<Textarea MenuMode="@MenuModeEnum.minimal" @bind-Value="@SomeObject.Comments" />
来源:https://stackoverflow.com/questions/57677035/tinymce-disappears-in-blazor-page