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 クラス文字列を構築するユーティリティ関数を自分で作成することにしました。
ユーティリティ関数の基本コンセプトは次のとおりです。
- この関数には、匿名オブジェクトを渡すことができます。
- この関数は .NET CLR の「リフレクション」機能を使い、引数のオブジェクトの
bool
型のプロパティを取得します。 - この関数は、そのプロパティの値が
true
であるプロパティに絞り込みます。 - 最後に、関数はこれらのプロパティ名とスペース区切り文字を連結した文字列を返します。
この基本コンセプトをクラスライブラリに実装しました。
クラス名は 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".)
まとめ
この実装をブラッシュアップし、このクラスライブラリを NuGet パッケージとして公開しました。
このライブラリに興味があれば、以下のリンクをたどってください。
すべてのソースコードは GitHub 上にあります。
Blazor で Happy coding :)