如何使用 Blazor 更改 div 元素的类

How to change classes of a div element using Blazor

提问人:bilpor 提问时间:1/8/2019 最后编辑:bilpor 更新时间:10/14/2022 访问量:69412

问:

我在cshtml页面中有一个典型的div元素,其形式为:

<div id="loginErrors" class="alert alert-danger hide-errors">@(ErrorMessage)</div>

在 Blazor 之前,我通常会使用 jQuery 在 div 中添加或删除类。但是,Blazor 正在尝试消除对 JavaScript 的需求,而我正在尝试使用尽可能少的 JSInterop。Blazor 中有没有办法做到这一点?hide-errors

因此,在 Blazor 中,我可以执行以下操作:

 @if (!string.IsNullOrEmpty(ErrorMessage))
 {
     <div id="loginErrors" class="alert alert-danger">@(ErrorMessage)</div>
 }
 else
 {
     <div id="loginErrors" class="alert alert-danger hide-errors">@(ErrorMessage)</div>
 }

或使用 JSinterop :

呼吁删除:

await JSRuntime.Current.InvokeAsync<object>("blazorExtensions.RemoveClass", "loginErrors", "hide-errors");

其中函数通常为:

RemoveClass: function (id, classname) {
    var tt = '#' + id;
    $(tt).removeClass(classname);
}

与添加类类似。上述两者都有效,但如前所述。我试图避免 JSInterop 路由,我不喜欢 div 元素被声明两次,即使只有一个会进入 DOM。

Blazor

评论


答:

57赞 Flores 1/8/2019 #1

就像您在普通 Razor 中一样:

@if (price>30)
{
    <p>The price is too high.</p>
}

编辑对于更新的问题,我猜你想要这个:

<div class="@((string.IsNullOrEmpty(ErrorMessage)? "hide-errors" : ""))">

评论

0赞 bilpor 1/8/2019
我试图避免这种情况,并使用相同的 id 声明了 2 个 div 元素,一个带有类 hide-errors,另一个没有。因此,我确实想实际删除或添加该类ifelse
0赞 Flores 1/8/2019
好。但是你问题中的其他目的是什么?它不添加任何功能。
1赞 Flores 1/8/2019
为什么需要身份证?
1赞 bilpor 1/8/2019
我们有 ID,因为 Specflow 需要 ID
23赞 user11623871 6/10/2019 #2

这非常简单,因为您可以在 Blazor 中动态更改 html 元素的任何部分,而无需使用 Javascript。我承认,经过这么多年,我花了一点时间才摆脱旧的 Javascript 思维方式,但一旦你这样做了,Blazor 就会摇滚!

在你的html的某个地方,使用一个变量作为你要进行动态样式(或其他)修改的任何html元素的类名(或其他属性)。

    <img class="@myImageClass" src="@myImg" />

在@functions中声明您创建的任何变量...

    @functions {
    string myImageClass { get; set; }
    string myImg { get; set; } // Swap out the image as well if you want. 

如果要最初将项目设置为某些内容,请使用 OnInit()

     protected override void OnInit()
     {
     myImageClass = "myImageVisible";
     myImg = "https://www.somesite.com/ImageToStartWith.png"

     }

在函数中的某个位置,将所需的类更改为您在样式部分中预定义的内容。

    private async Task DoSomething()
    {
      myImageClass = "myImageHidden";
      myImg = "https://www.somesite.com/NewImageToSwapIn.png"
      //Not sure what the point of swapping an image on a hidden element is 
      //but you get the idea. You can change anything you want anytime. 
    }

不要忘记事先定义一些要使用的样式。

     <style>
     .myImageVisible {
      display: block;
      }

     .myImageHidden{
      display: none;
      }
      </style>

享受。:)

评论

4赞 Linus Proxy 2/26/2020
对于每个编辑窗体中具有 25+ 个字段的 LOB 应用程序来说,这并不算什么,您必须在视图模型中处理 3-4 倍的属性数量。想想吧。您需要一个用于实际数据的属性,一个用于 css 类的属性,一个用于 disabled 属性的属性,一个用于 tabindex 的属性......等。与 JS 相比,您只需获取 ID 并直接设置属性,而无需将其保存在广泛的视图模型中。
1赞 Bart Czernicki 6/8/2020
@LinusProxy这就是 Blazor 组件的用武之地,你可以通过层次结构来执行其中的一些操作。还可以使用 HTML5/CSS3 解决其中一些类型的问题,而不必执行任何 Blazor (C#) 或 JavaScript。在这个特定示例中,可以使用 CSS3 过渡(不需要 JS/C#)。
2赞 Nick Kovalsky 7/19/2020 #3

对于完全的怪胎(我),创建一个剃须刀组件(xaml 爱好者梦想):

示例用法

<ContentView Size="Small" IsVisible="@IsOnline">

 <img src="@myImg" />

</ContentView>

结果:应用了适当类的 divs,对于 .class='size-small'Size="Small"

您可以向此类组件添加任何参数,并根据逻辑更改内部的类,从而保持主页清洁。

ContentView.razor

@if (IsVisible)
    {
    <div class="@sizeClass"> @ChildContent</div>
    }

@code {


    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public bool IsVisible { get; set; } = true;

    [Parameter]
    public string Size {
        get
        {
            return _size.ToString();
        }
        set
        {
            _size = Enum.Parse<MySize>(value);
            switch (_size)
            {
                case MySize.Big:
                    sizeClass = "size-big";
                    break;
                case MySize.Small:
                    sizeClass = "size-small";
                    break;
                default:
                    sizeClass = "";
                    break;
            }
        }
    }

    private MySize _size;

    private string sizeClass;

    public enum MySize
    {
        Default,
        Small,
        Big
    }

}
3赞 Dima Pavlenko 5/4/2021 #4

这是我在控制特定元素的 UI(例如突出显示单击的元素)的上下文中问自己的一个问题,以防其中有很多元素(例如列表)。

2 种常见方法(如其他人所述)是:

  1. 在元素 class=“@someProp some-other-class...” 属性中绑定页面/组件字符串属性,该属性可用于设置多个类(因为它只是一个字符串)或添加多个此类属性(用于更精细的条件控件)。
  2. 创建一个专用组件,其中包含将类或 CSS 值绑定到的所有必需属性。

但我想我想到了第三种方法,一种“介于两者之间”的技术,它提供了一个非常强大的 UI 控件,带有对象绑定(甚至是 2 向绑定),而无需处理单独的组件。因为有时你需要手动触发父组件 StateHasChanged(),比如当父组件和子组件之间存在各种依赖关系时,但视觉状态机制不会自动刷新。

只需创建一个包装类,用要控制的 CSS 值作为其属性来表示项目。位于同一页面/组件@code部分或某个共享文件夹上。

例如,我有一个 Slide 对象列表,由 Card 对象直观地表示(并因此包装),用户可以单击该对象进行选择和编辑。

项目模型:

public class Slide {
   public int SlideId { get; set; }
   public string Title { get; set; }
   public string Description { get; set; }
   public int SortIndex{ get; set; }
}

项目包装器模型:

public class Card {
   Slide Slide { get; set; }
   public string SelectedCssClass { get; set; }
   public string SomeOtherCssClass { get; set; }
   
   public void Reset() {
      SelectedCssClass = "";
   {
}

因此,在组件初始化期间,在 OnIntialized() 方法(如果您获取并等待数据列表,则为 OnInitializedAsync()))中,我用一个新的包装器对象包装每个项目。然后,在 @foreach() { } 循环中,列出包装的项目,我将一个 @onclick 事件处理程序附加到每个 div/card,传递该 card 对象的引用:

@foreach (Card card in Cards)
{
   <div class="card @card.SelectedCssClass" @onclick="@(e => setSlideToEdit(card))"
}

setSlideToEdit(card) { } 函数中,我可以通过简单地调用卡片来重置以前选择的幻灯片(存储在某个属性中)的样式。Reset() 方法,让绑定完成工作,然后使用新的绑定并设置卡。SelectedCssClass 属性(或添加另一个专用方法来设置预定义的方法)。

0赞 Liam 6/17/2022 #5

我选择了帕夫连科@Dima答案的更通用版本......

我有一个类,它包装了我想更改的对象:

public class HtmlWrapper<T>
{
    public T Item { get; set; }
    public string Class { get; set; }
    public HtmlWrapper(T item, string initialClass) 
    { 
        Item = item; 
        Class = initialClass; 
    }
}

在我的剃须刀页面中:

foreach(var user in UserList)
{
    <div class="@user.Class"><a @onclick="() => ClickOnUserAsync(user).ConfigureAwait(false)">@user.Item.Name</a></div>
}

@code {
    protected const string Class_User = "user";
    protected const string Class_Active = "user active";

    private List<HtmlWrapper<UserModel>>? _UserList;
    protected List<HtmlWrapper<UserModel>> UserList { get => _UserList ?? new(); set => _UserList = value; }

    protected override async Task OnInitializedAsync()
    {
        if (UserContext.UsersList is not null)
            UserList = UserContext.UsersList.Values.OrderBy(o => o.Name).Select(s => new HtmlWrapper<UserModel>(s, Class_User)).ToList();
    }

    protected async Task ClickOnUserAsync(HtmlWrapper<UserModel> user)
    {
        user.Class = user.Class == Class_User ? Class_Active : Class_User;
        StateHasChanged();
    }
}

评论

1赞 Naughton 10/13/2022
我认为您在第 3 行缺少一个左 paren [ change “)” to “()” ] ...