10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Blazor アプリで、bool スイッチ値に基づいて CSS クラス文字列を動的に構築する

Posted at

Angular アプリでの CSS クラス文字列の構築

Angular SPA プログラムをコーディングしているとき、このように CSS クラス文字列を制御するコードを書くことができます。

// my.component.ts
@Component({template:'my.component.html',...})
export class MyComponent {
  rotate: boolean;
  disabled: boolean;
  ...
<!-- my.component.html -->
<div [ngClass]="{'rotate':rotate, 'disabled':disabled}">...

上記のコードは、コンポーネントの rotate および disabled プロパティが true か否かに応じて、このようなDOMをレンダリングします。

<div class="rotate disabled">...

この Angular の ngClass ディレクティブは直感的でわかりやすいと思います。

Blazor だと、ちょっとつらい...

ところで、Blazor C#SPA プログラムをコーディングしているとき、CSS クラス文字列の制御は少し苦痛です。

Blazor においては、Angular の方法のようにではなく、自分で条件を判断して CSS クラス文字列を連結するコードを作成する必要がありました。

@* MyComponent.razor *@
<div class="@CssClass()">...

@code {
  bool Rotate;
  bool Disabled;
  
  // CSS クラス文字列の構築が必要なときに毎回、こんなコードを書かなきゃいけないの!?
  string CssClass() {
    var cssClass = new List<string>();
    if (this.Rotate) cssClass.Add("rotate");
    if (this.Disabled) cssClass.Add("disabled");
    return string.Join(' ', cssClass);
  }
  ...

自分はこのようなやり方では満足できませんでした。

さてどうしたものでしょうか。

基本コンセプト

ということで、、Angular の方法のように、匿名型オブジェクトから CSS クラス文字列を構築するユーティリティ関数を自分で作成することにしました。

ユーティリティ関数の基本コンセプトは次のとおりです。

  1. この関数には、匿名オブジェクトを渡すことができます。
  2. この関数は .NET CLR の「リフレクション」機能を使い、引数のオブジェクトの bool 型のプロパティを取得します。
  3. この関数は、そのプロパティの値が true であるプロパティに絞り込みます。
  4. 最後に、関数はこれらのプロパティ名とスペース区切り文字を連結した文字列を返します。

この基本コンセプトをクラスライブラリに実装しました。

クラス名は CssClassInlineBuilder とし、静的メソッド CssClass() として実装しました。

CssClass() 静的メソッドのソースコードは次のとおりです。

// CssClassInlineBuilder.cs
public static class CssClassInlineBuilder 
{
  public static string CssClass(object obj)
  {
    var boolPropNames = obj.GetType()
      // Enumarate all properties of the argument object.
      .GetProperties()
      // Filter the properties only it's type is "bool".
      .Where(p => p.PropertyType == typeof(bool))
      // Filter the properties only that value is "true".
      .Where(p => (bool)p.GetMethod().Invoke(obj, null))
      // Collect names of properties, and convert it to lower case.
      .Selec(p => p.Name.ToLower());

    // Concatenate names of filtered properties with space separator.
    return string.Join(' ', boolPropNames);
  }
}

このクラスライブラリを使用すると、Angular の方法のように、コードスニペットなしで CSS クラス文字列を動的に構築するコードを記述できます!

@* MyComponent.razor *@
<div class="@CssClassInlineBuilder.CssClass(new {Rotate, Disabled})">...

@code {
  bool Rotate;
  bool Disabled;
  ...

いい感じですね ;)

...しかしながら、自分はまだ、これでも満足できませんでした。

CssClassInlineBuilder.CssClass(new {...}) というコード、あまりに長すぎませんかね?

もっとシンプルに!

C#構文の1つが役に立ちました!

クラス名を省略するために using static ディレクティブを使用したのです。

@* _Imports.razor *@
...
@using static CssClassInlineBuilder

最終的に、メソッド名だけで記述することができるようになりました!

@* MyComponent.razor *@
<div class="@CssClass(new {Rotate, Disabled})">...

@code {
  bool Rotate;
  bool Disabled;
  ...

これで寿司も回せますね! :)
(Source code is on GitHub, inspired by "sushi-go-round".)

fig2

まとめ

この実装をブラッシュアップし、このクラスライブラリを NuGet パッケージとして公開しました。

このライブラリに興味があれば、以下のリンクをたどってください。

すべてのソースコードは GitHub 上にあります。


Blazor で Happy coding :)

10
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?