我有一些代码,它搜索文本字符串,并将某个子字符串的所有实例替换为包含 onclick 函数的元素。它看起来像这样:
private string ReplaceCitationLinks(string text, int documentIndex)
{
for (var i = 1; i <= documentIndex; i++)
{
var html = "<span class='citation-link' @onclick='() => ShowCitation(" + i + ")'>(Dokument " + i + ")</span>";
text = text.Replace("[doc" + i + "]", html);
}
return text;
}
然后在 HTML 中调用:
@((MarkupString)ReplaceCitationLinks("Test string [doc1]. Test string [doc2]", item.Citations.Count))
所以在这种情况下,我只希望字符串的 [doc1] 和 [doc2] 部分可单击。问题是 @onclick 不起作用。我想我可能需要用其他方式来做这件事。有谁知道我将如何实现这一点?
这里的问题是 Blazor 不知道您的标记包含 Blazor 语法,如
@onclick
。
有多种方法可以解决这个问题,但我建议创建一个组件
TextRenderer
。在此组件中,您添加一个参数 Text
来接收文本和一个参数 OnSpanClick
。然后重写 BuildRenderTree
,解析文本以找出占位符的位置,然后按原样返回非占位符标记,并在 RenderTreeBuilder
上调用合适的方法来构建 span
语法,如
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
// parse 'Text' to find placeholder positions
// iterate over 'Text' in steps defined by the placeholder positions,
// for example, start with 0, then jump to first placeholder at postion 10, then to second placeholder at position 56, etc.
// in those steps above, decide whether the text range is normal markup, then return it as
builder.AddContent(..., textRange);
// otherwise build your clickable span like
builder.OpenElement(..., "span");
builder.AddAttribute(..., "onclick",
EventCallback.Factory.Create(owner,
async () => await OnSpanClick.InvokeAsync(documentNumber)));
builder.AddContent(..., $"Dokument {documentNumber}");
builder.CloseElement();
}
然后在需要的地方使用这个组件,例如
<TextRenderer Text="@..." OnSpanClicked="@..." />
@onclick 是对 Action(或 Action 本身)的引用,它将在代码中执行。因此您不能将其作为字符串传递。
我最好的建议是将您的代码更改为如下所示:
@foreach(var i = 0; i < this.documents.Count(); i++) {
var item = this.documents[i]
<span class="citation-link" @onclick="() => @ShowCitation(i)">(@i) @documents[i]</span>
}
@code {
private List<string> documents = new (); // initialize anywhere on OnInitializedAsync
private void ShowCitation(int documentIndex){
// process your code by finding the given documentIndex in the documents variable
}
}