Vue.js の slot-scope、なかなか理解できなかったのですが、ようやく得心に至りました。 slot-scope、振舞いを抽出するのに便利なのか。
TODOリストの個々の要素への処理
たとえば、ここで todo-list
というコンポーネントがあるとします。
このコンポーネントの責務は、「個々の TODO をループさせ、その個々の要素に処理をすること」になります。
(デフォルト処理は"出力する"ようにしてます)
Vue.component('todo-list', { props: { todos: { type: Array, required: true } }, template: ` <ul> <template v-for="todo in todos"> <slot :todo="todo"> <li :key="todo.id"> {{ todo.text }} </li> </slot> </template> </ul> ` })
実際に、以下のようなデータでこのコンポーネントを実行してみると、 全データがリスト出力されることがわかります。
<div id="todo-list-demo1"> <todo-list :todos="todos"></todo-list> </div>
[ { id: 1, text: 'C++', isCompleted: true }, { id: 2, text: 'JavaScript', isCompleted: false }, { id: 3, text: 'Java', isCompleted: true }, { id: 4, text: 'Perl', isCompleted: false } ]
実行例
完了済の TODO のみ出力
では、次に完了済み TODO のみ出力したいという場合、また新しく一からコンポーネントを作るという方法もあるのですが、
既述の通り、todo-list
の責務は 「個々の TODO をループさせ、その個々の要素に処理をすること」にあるので、
ここでの「処理」を「isCompleted
が true の要素のみ出力する」に変えてしまえば良い。
これは todo-list
を一切触れることなく実現が可能です。
HTML の側に以下のように表記すれば良い。
<div id="todo-list-demo2"> <todo-list :todos="todos"> <li slot-scope="{ todo }" v-if="todo.isCompleted"> {{ todo.text }} </li> </todo-list> </div>
ここでは、<li>
タグとともに v-if
という条件の制御構造を todo-list
の body に加えています。
この body は、todo-list
の以下の <slot>
と対応します。
<slot :todo="todo"> <li :key="todo.id"> {{ todo.text }} </li> </slot>
実行例
というわけで
scope-slot を使えば、コンポーネントを使う側で、コンポーネントの動作をコントロールすることが可能になります。 React でいうと Render Prop のようなもの。