たまたまVue.jsのv-bindについて強く調べる機会があって、実はv-bindの持つ全ての機能について説明してる記事って無いかも?と思ったので、「ぜんぶ」とまではいかないかもしれないけど思いつく範囲のv-bindの機能を列挙するつもりです。
Vue.jsのバージョンは3に限定します(v2も調べ直すの面倒なので)。
v-bindの基本
Vue.jsのディレクティブの一つです。つまりテンプレートに記述するHTML属性っぽいところに記述できるVue.jsの構文の一つです。
ディレクティブがなんなのかのドキュメントはここ(英語)です。
v-bindのAPIとしてのドキュメントはここ(英語)です。
基本機能
HTML要素に使用すると、属性を動的に設定できます。コンポーネントに使用すると、コンポーネントのプロパティを動的に設定できます。
HTML要素に使用する例:
<template>
<input v-bind:type="myInputType">
</template>
この場合、出力されるHTMLは<input>のtype属性に、myInputTypeに保存された値が指定されます。
myInputType='password'の場合に出力されるHTMLの具体例は次です。
<input type="password">
コンポーネントに使用する例:
<template>
<MyComponent v-bind:message="myMessage" />
</template>
このコードは、<MyComponent>コンポーネントのmessageプロパティに、myMessageに保存された値が指定されます。HTMLの結果はコンポーネントの定義によるので割愛します。
基本構文
HTMLではv-bind:【属性名】="【JavaScript式】"のように記述します。記述は同じですがコンポーネントに使用するとv-bind:【プロパティ名】="【JavaScript式】"となります。
Vue.jsのディレクティブとして説明すると、ディレクティブ名がbindで、引数には属性名かプロパティ名を指定します。スクリプトにその属性かプロパティに与える値を取り出す式を記述するということになります。
(ディレクティブはv-【ディレクティブ名】:【引数】.【修飾子】="スクリプト"みたいな構造を持ちます。詳細はこちら(英語))
JavaScript式が書けるということは、次の例に書くv-bindは、いずれも有効なv-bindです。
<template>
<input v-bind:type="myInputType">
<input v-bind:type="myTypes.foo.bar">
<input v-bind:type="types[kind]">
<input v-bind:type="getType(foo)">
<MyComponent v-bind:my-str-prop="prefix + str" />
<MyComponent v-bind:my-num-prop="num * 42" />
<MyComponent v-bind:my-obj-prop="{ foo: 1, bar: 2, baz }" />
<MyComponent v-bind:my-arr-prop="[1, 2, 3, foo]" />
</template>
またv-bindには省略記法があり、
:【属性名】="【JavaScript式】"のように記述しても同じです。
<template>
<input :type="myInputType">
<input :type="myTypes.foo.bar">
<input :type="types[kind]">
<input :type="getType(foo)">
<MyComponent :my-str-prop="prefix + str" />
<MyComponent :my-num-prop="num * 42" />
<MyComponent :my-obj-prop="{ foo: 1, bar: 2, baz }" />
<MyComponent :my-arr-prop="[1, 2, 3, foo]" />
</template>
特別な使用
v-bind:class
ドキュメントはこの辺り(英語)です。
v-bind:classのオブジェクト形式
普通のclass属性として考えると文字列のみ利用できそうですが、v-bind:classにはオブジェクトを与えることができます。
与えるオブジェクトは、{ '【class名】': 【真偽値】 }のような形式のオブジェクトです。真偽値がtrueの場合は、そのclass名が適用されfalseの場合は適用されません。条件によってclassを制御する時に便利です(文字列結合と三項演算子など使用する必要はありません)。
<template>
<div v-bind:class="{ 'item--active': isActive, 'item--hidden': !isShown }"></div>
</template>
isActiveとisShownがどちらもtrueの時はitem--activeの値のみがtrueのため、item--activeだけがclass属性に付与されます。つまり次のHTMLが出力されます。
<div class="item--active"></div>
v-bind:classの配列形式
v-bind:classには配列を与えることができます。配列の要素には与えるclass名、およびオブジェクトを列挙します。すると配列で与えられたclass名が全て適用されます。
例:
<template>
<div v-bind:class="['foo','bar']"></div>
<div v-bind:class="['foo','bar', { 'item--active': isActive, 'item--hidden': !isShown }]"></div>
</template>
HTMLの出力:
<div class="foo bar"></div>
<div class="foo bar item--active"></div>
通常のclass属性と併用
通常の属性は、同じ属性に対して、v-bindと、普通の属性としての記述は併用できませんが、class属性と次に紹介するstyle属性は、併用することができます。
v-bind:class="..."で与えるclass名と、class="..."で与えるclass名はマージして適用されます。
例:
<template>
<div
class="foo bar"
v-bind:class="['baz','qux']">
</div>
</template>
HTMLの出力:
<div class="foo bar baz qux"></div>
v-bind:style
ドキュメントはこの辺り(英語)です。
v-bind:styleのオブジェクト形式
v-bind:styleもオブジェクトを与えることができます。
与えるオブジェクトは、{ '【style名】': '【styleの値】' }のような形式のオブジェクトです。文字列結合を使用して、styleを頑張って作り出す必要はありません。また、プロパティ名に指定する【style名】はキャメルケースでも有効です。
<template>
<div v-bind:style="{ color: myColor, fontSize: myFontSize }"></div>
</template>
myColorが"red"でmyFontSizeが"14px"の場合、次のHTMLが出力されます。
<div style="color: red; font-size: 14px;"></div>
v-bind:styleの配列形式
v-bind:styleには配列を与えることができます。配列の要素には与えるオブジェクトを列挙します。すると配列で与えられたstyleが全て適用されます。
例:
<template>
<div v-bind:style="[{ color: myColor }, { fontSize: myFontSize }]"></div>
</template>
HTMLの出力:
<div style="color: red; font-size: 14px;"></div>
自動プレフィックス
v-bind:styleとオブジェクトを使用して与えたスタイル名は、そのブラウザで動作するために必要なベンダープレフィックスを自動的に付与します。
例:
<template>
<div v-bind:style="{ 'line-clamp': 3 }"></div>
</template>
HTMLの出力(Chromeの場合):
<div style="-webkit-line-clamp: 3;"></div>
通常のstyle属性と併用
v-bind:styleとstyle属性は、併用することができます。
v-bind:style="..."で与えるstyleと、style="..."で与えるstyleはマージして適用されます。
例:
<template>
<div
style="color: red;"
v-bind:style="{ fontSize: '14px' }">
</div>
</template>
HTMLの出力:
<div style="color: red; font-size: 14px;"></div>
v-bind:key
ドキュメントはこの辺り(英語)です。
(本当はkey属性(特別な属性)はv-bindとは関係ないですが、併用することが多いと思うので書いておきます。)
key属性を与えると、Vueは実際のDOMを描画するためのヒントとして使用します。よく使用される例をいくつか書いておきます。
ちなみにkey属性は実際のHTMLには出力されません。
v-forと使用
v-for一緒に使用する場合は、最適化が主な目的です。
ドキュメントはこの辺り(英語)です。
<template>
<li v-for="item in items"
v-bind:key="item.id">
{{ item.text }}
</li>
</template>
v-forが<template>にある場合は、v-bind:keyは<template>に記述します。
<template>
<ul>
<template v-for="item in items"
v-bind:key="item.id">
<li>{{ item.text1 }}</li>
<li>{{ item.text2 }}</li>
</template>
</ul>
</template>
<transition-group>と使用
<transition-group>でアニメーションを意図通りに動かすためには、<transition-group>の子要素でkeyを使用します。
ドキュメントはこの辺り(英語)です。
<template>
<transition-group name="list">
<span v-for="item in items" v-bind:key="item.id">
{{ item.text }}
</span>
</transition-group>
</template>
より高度な構文
先に書いた、基本構文以外の構文的な機能を書きます。
動的属性名(プロパティ名)
v-bindはディレクティブなので動的引数を使用できます。
つまり、v-bind:【名前】で指定していた【名前】は動的に変更できます。
<template>
<input v-bind:[foo]="bar">
</template>
これはfooが"data-hello-bind"で、barが"BAR DATA"だった場合に出力されるHTMLの具体例は次です。
<input data-hello-bind="BAR DATA">
もちろん省略記法でも使用できます。
<template>
<input :[foo]="bar">
</template>
引数無し
v-bind="object"と指定するとオブジェクトのプロパティとして与えた値を一括で適用します。
つまり、
<template>
<input v-bind="{ type:'text', maxlength: 3 }">
</template>
は、HTMLでは、
<input type="text" maxlength="3">
となります。
.camel修飾子
v-bind:【名前】で指定した【名前】を、キャメルケースに変換して実際に与えるらしいです(自分は使ったことないです。SVGで現れるキャメルケースの属性名の時に有用という噂を聞いたことがありますがよく知りません)。
詳細はこちら(英語)を参照してください。
次のような形で使用します。
<svg v-bind:view-box.camel="viewBox /* viewBox='0,0,0,0'*/"></svg>
出力はこのような形。
<svg viewBox="0,0,0,0"></svg>
より高度な使用
<slot>に使用
スコープ付きスロットはv-bindを使用します。
ドキュメントはこの辺り(英語)です。
<slot>でv-bindを使用すると、子コンポーネントからv-bindで与えられた値を、スロットコンテンツを生成する親コンポーネント側で使用できます。これはスコープ付きスロットと言われます。
例:
<template>
<div class="child">
<slot v-bind:foo="myFoo" />
</div>
</template>
<script>
export default {
data() {
return { myFoo: "Hello" }
}
}
</script>
<template>
<div class="parent">
<ChildComponent>
<template v-slot="{ foo }">
{{ foo }} world
</template>
</ChildComponent>
</div>
</template>
HTMLの出力:
<div class="parent">
<div class="child">
Hello world
</div>
</div>
詳細はドキュメントを参照してください。
v-bind:ref
ドキュメントはこの辺り(英語)です。
普通にref="foo"と書くと、これを書いた要素(またはコンポーネントのインスタンス)が$refs.foo経由でアクセスできるようになりますが、v-bind:refを使用して、コールバック関数を与えるとコールバック関数によって、これを書いた要素(またはコンポーネントのインスタンス)を処理できます。
<template>
<div v-bind:ref="(el) => child = el /* childプロパティで受け取ります */">Foo</div>
</template>
<script>
export default {
data() {
return { child: null }
},
mounted() {
console.log(this.child) /* <div>Foo</div> が出力されます。 */
}
}
</script>
v-bind:is
ドキュメントはこの辺り(英語)です。
isは<component>というVueの組み込みコンポーネントのプロパティです。
詳細はドキュメントを参照してください。
HTML属性と値
いくつかの値は、それを与えるHTML属性によって、振る舞いが違います。
ドキュメントとしてはこの辺り(英語)とRFCだとこれ(英語)です。
null または undefined
nullかundefinedを与えると属性自体が付与されません。属性ごと与えたくない(属性を削除)したい場合は、nullかundefinedを与えておけば良さそうです。
空白文字列('')では属性自体はついたままなので要注意ということでもあります。
<template>
<input v-bind:type="nullValue">
<input v-bind:type="undefinedValue">
<input v-bind:type="falseValue">
<input v-bind:type="emptyValue">
<input v-bind:type="zeroValue">
</template>
<script>
export default {
data () {
return {
nullValue: null,
undefinedValue: undefined,
falseValue: false,
emptyValue: '',
zeroValue: 0
}
},
}
</script>
<input>
<input>
<input type="false">
<input type>
<input type="0">
false
真偽値属性(例えば<input>のdisabled)の場合は空白文字列('')以外のfalseな値を与えると属性自体が付与されません。
こちらも空白文字列('')では属性自体はついたままなので要注意です。特に属性としてはtrue扱いであることに注意してください。
<template>
<input v-bind:disabled="nullValue">
<input v-bind:disabled="undefinedValue">
<input v-bind:disabled="falseValue">
<input v-bind:disabled="emptyValue">
<input v-bind:disabled="zeroValue">
</template>
<script>
export default {
data () {
return {
nullValue: null,
undefinedValue: undefined,
falseValue: false,
emptyValue: '',
zeroValue: 0
}
},
}
</script>
<input>
<input>
<input>
<input disabled>
<input>
まとめ
v-bindの説明というより、Vueが特別に扱う属性とプロパティの機能説明って感じになってしまった気もしますね(汗)
再度書きますが、Vue 3限定なので、Vue 2では使用できないことも書いてあります。
他のディレクティブも書いてみたい気持ちもあったけど、v-bindだけで結構疲れたのでもういいかな。
しかし、本当にこれで全部なのかどうかは自信ないです。。