【Nuxt 2】小ネタ集
はじめに
この記事では、これまでの記事で記載できていない Vue.js/NuxtJs の機能や設定について記述していきます。 小ネタ集というよりは、情報提供できていないものを消化しているだけです。
$nextTick()
$nextTick()
は、DOM 更新後に実行したい処理を記述します。
例えば、v-if
で表示した要素内の入力欄に、フォーカスを設定したいとします。
<template>
<div>
<div v-if="show">
<input ref="input1" />
</div>
<button @click="onClick">表示</button>
</div>
</template>
<script>
export default {
data: () => ({
show: false,
}),
methods: {
onClick() {
this.show = true
this.$refs.input1.focus()
},
},
}
</script>
この実装では、表示したタイミングでエラーとなります。
this.show = true
により、要素を表示するために DOM が更新されます。
しかし、その結果を待たずしてthis.$refs.input1.focus()
が実行されてしまうため、そんな要素はないよというエラーになります。
このような場合に$nextTick()
を使用します。
onClick() {
this.show = true
this.$nextTick(() => {
this.$refs.input1.focus()
})
}
これにより DOM が更新された後に処理が実行される、つまり対象の要素がある状態で処理が実行されるため、フォーカスが正しく設定されます。
model
通常コンポーネントでv-model
を実装するには、props
にvalue
を定義することで紐付け、input
イベントによって値を更新します。
<template>
<input type="text" v-model="inputValue" />
</template>
<script>
export default {
props: {
value: {
type: String,
default: undefined,
},
},
computed: {
inputValue: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
},
},
},
}
</script>
これをvalue
以外のプロパティに紐付けたり、input
以外のイベントで値を更新したい場合にmodel
を指定します。
<template>
<input type="text" v-model="inputValue" />
</template>
<script>
export default {
model: {
prop: 'text',
event: 'change',
},
props: {
text: {
type: String,
default: undefined,
},
},
computed: {
inputValue: {
get() {
return this.text
},
set(value) {
this.$emit('change', value)
},
},
},
}
</script>
inheritAttrs
以下のようなコンポーネントがあったとします。
<template>
<a><slot /></a>
</template>
これを以下のように使用するとどうなるでしょうか。
<simple-link href="https://google.com">Google</simple-link>
答えは、以下のように展開され、リンクが機能します。
<a href="https://google.com">Google</a>
このようにprops
で指定していない属性は、コンポーネントのルート要素に反映されてしまいます。
これを防ぐためには、inheritAttrs
をfalse
に設定します。
<template>
<a><slot /></a>
</template>
<script>
export default {
inheritAttrs: false
}
</script>
これにより、style
とclass
以外のprops
に設定されていない属性は無視されるようになります。
component
コンポーネントを動的に変更したい場合に<component>
を使用します。
<template>
<div>
<select v-model="selected">
<option v-for="c in components" :key="c" :value="c">{{ c }}</option>
</selected>
<component :is="selected" />
</div>
</template>
<script>
export default {
data: () => ({
selected: 'MyComponent1',
components: [
'MyComponent1',
'MyComponent2',
'MyComponent3'
]
})
}
</script>
<component>
の:is
にコンポーネント名をバインドすることで表示が動的に切り替わります。
動きとしてはv-if
と同じく、DOM 操作により表示・非表示が切り替わります。
プロパティのバインドも可能ですが、すべてのコンポーネントに適用されるため、個別に設定したい場合は素直にv-if
などを使う方が無難です。
keep-alive
以下のような単純なコンポーネントを作成します。
<template>
<input type="text">
</template>
これを以下のようにv-if
で非表示にすると、コンポーネントは初期化されます。
つまり、非表示にすれば入力した内容は消えてしまいます。
<template>
<div>
<simple-form v-if="show" />
<button @click="show = !show">click</button>
</div>
</template>
<script>
export default {
data: () => ({
show: true,
}),
}
</script>
これを<keep-alive>
で囲むことで、DOM からは消えますが、コンポーネントの状態をキャッシュすることができます。
つまり、非表示にしても入力した内容は失われません。また表示時にmounted
などのライフサイクルは実行されません。
<keep-alive>
<simple-form v-if="show" />
</keep-alive>
これだけであればv-show
と大きな変わりはありません。
<keep-alive>
は、上記の<component>
と組み合わせて使います。
<keep-alive>
<component :is="selected">
</keep-alive>
<keep-alive>
は、キャッシュを制御するための以下の 3 つの属性を持ちます。
max
max
は、キャッシュする最大数を設定します。
例えば以下で、MyComponent1
→MyComponent2
→MyComponent3
と切り替えるとMyComponent1
の情報は削除されます。
<keep-alive>
<component :is="selected" max="2">
</keep-alive>
include
include
は、キャッシュするコンポーネントを設定します。
ここに設定されていないコンポーネントはキャッシュされません。
<keep-alive>
<component :is="selected" :include="['MyComponent1', 'MyComponent2']">
</keep-alive>
exclude
exclude
は、キャッシュしないコンポーネントを設定します。
ここに設定されていないコンポーネントはキャッシュされます。
<keep-alive>
<component :is="selected" :exclude="'MyComponent3'">
</keep-alive>