You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor如何在按钮点击事件中同时执行C#与JS函数?

问题描述

我有两个按钮:一个用于执行JavaScript函数,代码如下:

<button class="btn-orange btn" onclick="expand(this.closest('.profile'))">JavaScript</button>

另一个用于执行C#逻辑并根据布尔值切换图标,代码如下:

<button class="btn-orange btn"
   @onclick="@(() =>
   {
      if (tempBool)
      {
         tempBool = !tempBool;
      }
      else
      {
         tempBool = true;
      }
   })">
   <i class="fa @(tempBool ? "fa-compress" : "fa-expand")" aria-hidden="true"></i>
</button>

我希望将这两个按钮的功能合并,即实现按钮点击事件同时执行C#逻辑与JavaScript函数。尝试过使用OnClientClick事件、调用JsRuntime.InvokeVoidAsync("expand(this.closest(.profile))");,以及将两者放在同一个onclick事件中,但均未成功。

我的JavaScript代码位于EventPageExpandable.js:

function expand(card) {
    card.classList.toggle('profile--expanded');

    // If card is not expanded after toggle, add 'unexpanded' class
    if (!card.classList.contains('profile--expanded')) card.classList.toggle('profile--unexpanded');

    // Else if card is expanded after toggle and still contains 'unexpanded' class, remove 'unexpanded'
    else if (card.classList.contains('profile--expanded') && card.classList.contains('profile--unexpanded')) card.classList.toggle('profile--unexpanded');
}

尝试的JsRuntime调用方式如下:

await JsRuntime.InvokeVoidAsync("EventPageExpandable.expand", "this.closest('.profile')");

或者:

await JsRuntime.InvokeVoidAsync("expand", "this.closest('.profile')");

但两种方式都无法正常工作,请问如何实现该需求?

解决方案

核心问题分析

你之前的调用失败是因为向JS函数传递了字符串"this.closest('.profile')",而非实际的DOM元素。JS函数expand需要接收DOM节点才能调用classList相关方法,字符串参数无法满足要求。

正确实现步骤

1. 定义元素引用与状态变量

在Blazor组件代码中,添加用于获取.profile元素的ElementReference,以及状态变量tempBool:

@inject IJSRuntime JsRuntime

<!-- 给.profile元素添加@ref绑定 -->
<div class="profile" @ref="_profileElement">
    <!-- 合并后的按钮 -->
    <button class="btn-orange btn" @onclick="HandleToggle">
        <i class="fa @(tempBool ? "fa-compress" : "fa-expand")" aria-hidden="true"></i>
    </button>
    <!-- 其他内容 -->
</div>

@code {
    private ElementReference _profileElement;
    private bool tempBool = false;

    private async Task HandleToggle()
    {
        // 执行C#逻辑:简化原有的if-else,直接取反状态
        tempBool = !tempBool;

        // 调用JS函数,传入实际的DOM元素引用(Blazor会自动转换为JS可识别的DOM节点)
        await JsRuntime.InvokeVoidAsync("expand", _profileElement);
    }
}

2. 确保JS文件正确引入

确认EventPageExpandable.js已在项目中正确加载,比如在wwwroot/index.html(WebAssembly)或Pages/_Layout.cshtml(Server)中添加:

<script src="EventPageExpandable.js"></script>

替代方案(无需ElementReference)

如果不想使用ElementReference,也可以给.profile元素添加唯一ID,然后在JS中通过ID查找元素:

C#代码:

private bool tempBool = false;
private async Task HandleToggle()
{
    tempBool = !tempBool;
    // 传入元素ID让JS查找
    await JsRuntime.InvokeVoidAsync("expandById", "unique-profile-id");
}

修改JS函数:

function expandById(cardId) {
    const card = document.getElementById(cardId);
    if (!card) return;
    
    card.classList.toggle('profile--expanded');
    if (!card.classList.contains('profile--expanded')) card.classList.toggle('profile--unexpanded');
    else if (card.classList.contains('profile--expanded') && card.classList.contains('profile--unexpanded')) card.classList.toggle('profile--unexpanded');
}

同时给.profile元素添加ID:

<div class="profile" id="unique-profile-id">...</div>

内容的提问来源于stack exchange,提问作者SideSky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:48:28