Blazor的onclick事件未被触发。

33

我试图像这个示例https://blazorfiddle.com/s/counter一样实现一个简单的onclick事件处理程序,但在我的解决方案中无法工作。由于未知原因,该事件仅在运行网页时触发。

HTML页面与Blazor组件很好地显示,但当我点击按钮时,什么也没有发生。

我使用的是VS 2019 .Net Core 3.0. ASP.NET MVC项目

Counter.razor 文件:

@using Microsoft.AspNetCore.Components

<p>Current count: @currentCount</p>

<button class="btn btn-primary" onclick="@IncrementCount();">Click me</button>

@code {
    int currentCount = 0;

    private async Task IncrementCount()
    {
        await Task.Run(() => currentCount++);
    }
}

Index.cshtml:

@using WebApplication2.Views.Components

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

@(await Html.RenderComponentAsync<Counter>(RenderMode.Server, new { }))

startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddHttpClient();
    services.AddRazorPages();
    services.AddServerSideBlazor();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

浏览器中的按钮:

<button class="btn btn-primary" onclick="System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,WebApplication2.Views.Components.Counter+<IncrementCount>d__2];">Click me</button>

浏览器错误:

浏览器中的漏洞


你的代码在某些地方不同 - 建议您重新检查,例如计数器页面上缺少@page指令... - jazb
应该是 <button class="btn btn-primary" @onclick="IncrementCount();">点击我</button> - Neves
1
你最终解决了这个问题吗?我也遇到了完全相同的问题。 - YodasMyDad
@leen3o: @onclick="IncrementCount". 只需创建一个新项目并查看计数器页面即可。 - H H
@sanepete: OP已经离开了:"最后一次出现已超过3年"。 - undefined
显示剩余6条评论
19个回答

39
这是与问题相关的最流行的问题:Blazor onclick事件不会被触发。除了解决了原始问题但无法解决我的答案之外,我想补充一点:

<script src="~/_framework/blazor.server.js"></script>需要放在声明事件的组件之后,而不是在<head />标签中。可能要放在_Host.cshtml或需要Blazor组件的MVC视图的body标签的最底部。如果不这样做,Blazor语法仍然可以工作,项目将会编译,并且大多数功能都会按预期工作,但是事件不会被触发。

我刚刚花了几个小时才弄清楚这一点。

另外,如果@onclick.razor文件中根本无法被识别为Blazor代码(尤其是在组件库中),请确保在项目的最顶部添加_Imports.razor文件,并包含以下内容:

@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop

如果由于某种原因找不到某些命名空间,可以将它们作为NuGet包添加进来。

请特别注意项目顶部的_Imports.razor文件。我将此文件放在Pages目录中,所有内容都可以呈现,但没有任何交互性可用。 - Richard Davison
非常感谢!我正在将“using”移动到“_imports”,但某些页面上的“onclick”停止工作了。我在您的列表中漏掉了一些“using”语句。 - Michael Z.
当我移动blazor.server.js <script>标签的位置时,我没有看到任何区别。对我有用的是像上面描述的那样添加_Imports.razor。一旦我添加了它,'@onclick'的语法高亮就起作用了,更重要的是,事件被触发了。 - Rob3C
将_Imports.razor添加到Components文件夹中,这也解决了我的问题,谢谢。 - AFract

26

我认为您的onclick事件调用方式有误,它们已经更改了引用函数的方式:

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

现在,@符号在@onclick前面,而不是在函数名称前面。


我已经尝试过这个了。我认为这不正确,因为在浏览器中,按钮看起来像:<button class="btn btn-primary" @onclick="IncrementCount();">Click me</button>。 - micsp24
如果您正在使用 .NET 3.0 的发布版本,则代码将无法编译。如果您尝试按照您发布的方式运行代码,它将在 Blazor Fiddle 中失败。但是,如果您将其更改为新的结构,则可以成功编译并正常工作。 - David Masterson
此外,如果您跟随您提供的Blazor Fiddle示例链接,您会发现他们已经在Preview 7到3.0版本之间更改了结构。而且,您所说的唯一不起作用的是onclick。 - David Masterson
2
这个答案应该可以(另外();部分不需要) - Robert Perry
(); 这部分会导致程序无法运行甚至无法编译。 - undefined

18
这个答案仅适用于 .net 8,其中静态渲染是默认的。.net 8引入了渲染模式的概念,现在在页面级别或全局级别都是必需的。默认情况下是静态渲染,这意味着组件的渲染与其编写的方式完全一样,Blazor引擎不会添加任何交互性。如果您只有纯静态的HTML,并且不需要交互性的开销,这是很好的。另一方面,如果您使用的是早期版本,并且您的点击事件根本没有被处理,而且没有明显的原因,这可能会让您感到惊讶。
要添加交互性,您有两个选项。
组件级解决方案 在文件顶部检查此指令:
@rendermode InteractiveServer

如果它丢失了,那么事件将不会被触发。 在客户端(wasm)上,它将是这样的:
@rendermode InteractiveAuto

全球解决方案 在App.razor文件中更新Routes元素:
<body>
    <Routes @rendermode=RenderMode.InteractiveServer />
    <script src="_framework/blazor.web.js"></script>
</body>

全局解决方案允许您在MainLayout.razor中使用交互元素,而这在每个组件解决方案中是不支持的。如果您正在进行类似于连接“暗”模式并且需要将类应用于您的HTML的顶层,以便它应用于所有内容的操作,这将非常有用。

2
这对我来说是一个解决方案,但在 .net 8 版本中,语法已更改为 @rendermode InteractiveServer - undefined
我已经更新了答案以适应新的语法。 - undefined
感谢 @Vita 提供的建议修改。随着 .net 8 即将发布,这个问题和答案变得出奇地受欢迎。 - undefined

14

我曾经遇到过完全相同的问题,但找到了解决办法。

https://dev59.com/k1MH5IYBdhLWcg3wxic9#58444907

你需要在 Components 文件夹中添加一个 _Imports.razor 文件,并加入以下 using 语句。

@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop

4
这对我解决了问题。谢谢!! - John Royceton Arthur
3
加入 Microsoft.AspNetCore.Components.Web 命名空间对我很有帮助!感谢提示。 - roemel
我在我的Pages文件夹中有一个_Import.razor.cs,我还必须在我的Components文件夹中添加一个。 - reven
将_Imports.razor添加到Components文件夹中也为我解决了问题,谢谢。 - AFract

3

我刚遇到了一个非常奇怪的问题:这段代码没有被触发。

<div ... @onclick=@(_ => OnClick.InvokeAsync(EventArgs.Empty))></div>

问题的根本原因仍不清楚,但解决方法(或者说是一个变通的方法)是使用方法名替换lambda。
<div ... @onclick=OnClickHandler></div>

@code {
  private void OnClickHandler()
  {
    OnClick.InvokeAsync(EventArgs.Empty);
  }
}

3
我尝试找出大部分关于在MVC应用程序中使用Blazor的解决方案,有些不完整,所以我试图准备一些对我有效的复杂说明。如果您正在使用MVC应用程序内的Blazor,则必须执行以下操作。
转到_Layout.cshtml或index.html,在底部脚本部分添加:
<script src="~/_framework/blazor.server.js"></script>

在同一个文件_Layout.cshtml或index.html中,在标题或meta标签之后的head标签部分添加以下内容:
<base href="/" />

或者另外一种选择。
<base href="~/"/> 

在您的 Blazor 组件目录中创建 _Imports.razor 文件,并向其中添加以下 using 语句:
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop

另外,您也可以直接在组件文件的开头添加这些语句。

使用onclick如下:

如果您想传递参数:

@onclick="(()=>YourEvent(yourParams))"

或者你想要直接调用:

@onclick="YourEvent"

谢谢,我正在将之前的项目(Razor Pages)迁移到Blazor。我发现了head选项的缺失。 - undefined

3

对我来说,解决方案与这里的其他答案相差很大。我正在使用Cloudflare CDN来帮助提供我的Blazor Server应用程序。

最后,我需要在Cloudflare中关闭“HTML Minification”才能使我的onclick事件再次正常工作。

在Cloudflare的“速度”设置部分中关闭此设置:

enter image description here

有关解决此问题的其他选项,请参考以下博文:

Tobias Zimmergren的“使用Cloudflare的HTML缩小功能破坏了ASP.NET Core Blazor与SignalR一起使用”的博文

我也遇到了同样的使用Scully、Angular和Cloudflare时的HTML缩小问题

附加有用的博客文章:https://gordonbeeming.com/blog/blazor-server-events-not-triggering-when-hosted-behind-cloudflare

1
这个对我也解决了问题,谢谢。 - Gordon Beeming

3

应该是 <button @onclick=IncrementCount


2

在我的情况下,我像这样在Startup.cs中添加了StaticFileOptions(在我的MVC ASP.Core项目中使用了此代码)

app.UseStaticFiles(new StaticFileOptions()
{
   OnPrepareResponse = ctx =>
   {
       const int duration = 60 * 60 * 24;
       ctx.Context.Response.Headers[HeaderNames.CacheControl] = $"public,max-age={duration}";
   }
});

然后返回到。
 app.UseStaticFiles();

然后它开始工作了。


2
这对我也起作用了!在浏览器控制台中出现“Failed to load resource _framework/blazor.server.js”,但一旦我恢复到只使用app.UseStaticFiles(),一切都正常工作了。 - Charalampos Hadjiantoniou
我曾经遇到过同样的问题。在"OnPrepareResponse"中添加 "if (path.EndsWith("blazor.server.js")) return;" 解决了这个问题。 - rBalzer

1

也许需要了解执行方法的返回值和方法类型(即委托)之间的区别,例如 Action

IncrementCount(); //is a method that returns void (or string, or a Task, if you want)
var returnValue = MyMethod2();


//these declare and initilize delegate variables
var action = IncrementCount;
var action2 = MyMethod;
Func<int> myFunc = MyMethod2;
MyDelegate myDel = MyMethod3;

你需要做的是为 @onclick 指令 提供一个委托,而不是使用旧语法或返回值(尽管这是可能的)。
<button @onclick=@Hahaha()>Click me</button>
<button @onclick=@Foo>Click me</button>
<button onclick="console.log('Hahaha Foo')">Click me</button>
<button onclick=@Baar()>Click me</button>
@code {
Action Hahaha(){
return Foo;
}
void Foo() {
i = 5;
}
}
string Baar()
{
    return "console.log('Boofar')";
}

onclick="@IncrementCount();"这段代码至少有三个错误。

  • 如果你不想提供字符串,为什么还要使用"
  • 既然没有block,为什么要使用;?要了解@directive
  • 没有使用@onclick。
  • 使用方法返回的任务对象的隐式字符串转换,并不是此处所需的。

框架会完全按照您的要求执行:
将任务强制类型转换为字符串,并使用隐式的ToString()方法,附加一个';',并将其作为html属性onclick的JS代码传递。请注意,这仅适用于非void方法,因为void方法甚至都不会返回任何内容,因此不能用作在此处推断的字符串表达式!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接