IonicのIonItemを参考にしてslot属性の使い方を理解する
Ionic Frameworkは各コンポーネントによって属性は違うのですが、アイテムコンポーネントには大体 slot
属性があります。これがどういったものであるかから、実装までをみていきましょう。
Web Componentsとしてのslot
Ionicのコンポーネントは、 color
や mode
など、独自の属性も多くありますが、 slot
属性はWeb ComponentsのShadow DOMに定められている slot
要素にDOMを挿入するための標準仕様です。
例えば、Ionic Frameworkの IonItem
の場合、テンプレートは以下のようになっています(slotまわりだけを抽出しており、他は割愛しています)
<ion-item>
<slot name="start"></slot>
<div class="item-inner">
<div class="input-wrapper">
<slot></slot>
</div>
<slot name="end"></slot>
</div>
</ion-item>
ion-item
以下がShadow DOMとなっています。そして、このテンプレートは以下のように利用します。
<ion-item>
<ion-icon name="close" slot="start"></ion-icon>
<ion-label>
<h2>H2 Title Text</h2>
<p>Button on right</p>
</ion-label>
<ion-button fill="outline" slot="end">View</ion-button>
</ion-item>
すると、上記のHTMLは slot[name]
が一致する部分に挿入されます。つまり、
-
ion-thumbnail[slot=start]
はion-item > slot[name=start]
-
ion-button[slot=end]
はion-item > .item-inner > slot[name=end]
- slotが指定されていない
ion-label
は、ion-item > .item-inner > .input-wrapper > slot
の中に挿入されます。Ionic FrameworkはWeb標準に基づいてつくられておりますので、ここらへんはWeb Componentsの仕様そのままですね。
slotのスタイリング
ではスタイリングはどうなってるかを簡単にみてみましょう。まず、 slot はCSSで指定する時、 ::slotted()
で指定することができます。ですので、上記のスタイリングの一部はこのようになっています。
<ion-item>
<slot name="start"></slot>
<div class="item-inner">
<div class="input-wrapper">
<slot></slot>
</div>
<slot name="end"></slot>
</div>
</ion-item>
::slotted(ion-icon) {
font-size: 1.6em;
}
::slotted(ion-button) {
--margin-top: 0;
--margin-bottom: 0;
--margin-start: 0;
--margin-end: 0;
z-index: 1;
}
::slotted(ion-label) {
flex: 1;
}
slot
指定されてる ion-icon
は font-size: 1.6em
に指定されています。 ion-button
はデフォルトのスタイリングを打ち消す形で margin
が0に設定されており、また、 ion-label
は親にあたる .input-wrapper
があることから flex:1
に指定されています。複数の ion-label
があった場合の時のためですよね。
このデザインで肝になるのは、 .item-inner
と .input-wrapper
です(一部割愛しています)
.item-inner {
display: flex;
// This is required to work with an inset highlight
position: relative;
flex: 1;
flex-direction: inherit;
align-items: inherit;
align-self: stretch;
}
.input-wrapper {
display: flex;
flex: 1;
flex-direction: inherit;
align-items: inherit;
align-self: stretch;
text-overflow: ellipsis;
overflow: inherit;
box-sizing: border-box;
}
[slot=start]
がついた属性は基本的に横幅の上限があるアイテム( ion-icon
や ion-button
など)が来ますので、 slot
が空のパーツは残った空白を埋める必要があります。そこで、 .item-inner
は align-self: stretch
が指定されています。 .item-inner
以下の input-wrapper
も同様です。
これにより、「 [slot=start]
がまず場所をとり、.item-inner
内で次に [slot=end]
が場所をとって、残りが無名のslotに割り振られるという構造になっています。
まとめ
フレームワーク設計の際に、アイテムの親子関係やユースケースがよく練られてることが伺える一例だと思います。ソースコードを読んでるとこういう設計の意図が伺えますので、ぜひより詳しくなりたい方はコードを読むようにしてください。
それではまた。
Discussion