Vue2 + Options APIの記述のVue3 + <script setup>での書き方
Vue2 + Options APIからComposition APIをぶっ飛ばしてVue3 + <script setup>に乗り換えたら、記述が変わりまくっててインターネット浦島太郎状態になってしまったので、両者の対応する書き方をまとめた
とは言っても、Composition APIと<script setup>の記述はあまり違わないため、ほとんどOptions APIとComposition APIの対応する書き方のまとめみたくなってるかもしれない
※個人的なメモ程度のものですが、間違いに気づいた場合は指摘していただけると嬉しいです
使用するコンポーネントの定義
インポートするだけで使用可能になったため、必要なくなった
というかコンポーネントの定義に限らず、トップレベルで宣言されたものはテンプレートでそのまま使用可能になった
Vue2 + Options APIでの書き方
<template>
<Hoge />
</template>
<script>
import Hoge from '@/components/Hoge.vue';
export default {
components: {
Hoge,
},
}
</script>
Vue3 + <script setup>での書き方
<script setup>
import Hoge from '@/components/Hoge.vue';
</script>
<template>
<Hoge />
</template>
ブロックの順序
今までは<template>
, <script>
, <style>
の順だったが、<script setup>では<template>
と<script>
が逆になる
Vue2 + Options APIでの書き方
<template>
</template>
<script>
</script>
<style>
</style>
Vue3 + <script setup>での書き方
<script setup>
</script>
<template>
</template>
<style>
</style>
data
ref
またはreactive
でラップしてリアクティブにする
オブジェクトにはreactive
、それ以外にはref
を使うらしいが、全部ref
でも良さそう
値へのアクセスはvalue
プロパティを見ることで可能、テンプレート内では.value
を省略できる
参考:
Vue2 + Options APIでの書き方
<template>
<div>{{ count }}</div>
</template>
<script>
// ~~~~略~~~~
data() {
return {
count: 0,
}
},
created() {
console.log(this.count);
}
</script>
Vue3 + <script setup>での書き方
<script setup>
import { ref } from 'vue';
const count = ref(0);
console.log(count.value);
</script>
<template>
<div>{{ count.value }}</div>
</template>
props
defineProps
を使って定義する(インポートは必要ない)
Vue2 + Options APIでの書き方
<template>
<div>{{ initialCount }}</div>
</template>
<script>
// ~~~~略~~~~
props: {
initialCount: Number,
},
created() {
console.log(this.initialCount);
}
</script>
Vue3 + <script setup>での書き方
<script setup>
const props = defineProps({
initialCount: Number,
});
console.log(props.initialCount);
</script>
<template>
<div>{{ initialCount }}
</template>
emit
defineEmits
を使ってカスタムイベントを定義したうえでemit
する
こちらもdefineProps
と同様にインポートは必要ない
以下はParent.vue
からChild.vue
にcount
の値をprops
で渡し、Child.vue
のボタンがクリックされたらcount
の値を+10してParent.vue
に渡し、count
の値を変更するサンプル
Vue2 + Options APIでの書き方
<template>
<button @click="$emit('update-count', count + 10)">add 10</button>
</template>
<script>
// ~~~~略~~~~
props: {
count: Number,
}
</script>
<template>
<div>
<p>{{ count }}</p>
<Child :count="count" @update-count="updateCount" />
</div>
</template>
<script>
import Child from '@/components/Child.vue';
// ~~~~略~~~~
components: {
Child,
},
data() {
return {
count: 0,
}
},
methods: {
updateCount(newCount) {
this.count = newCount;
},
}
</script>
Vue3 + <script setup>での書き方
<script setup>
const props = defineProps({
count: Number,
});
const emit = defineEmits([
'update-count',
]);
</script>
<template>
<button @click="emit('update-count', count + 10)">add 10</button>
</template>
<script setup>
import { ref } from 'vue';
import Child from '@/components/Child.vue';
const count = ref(0);
const updateCount = (newCount) => {
count.value = newCount;
};
</script>
<template>
<div>
<p>{{ count }}</p>
<Child :count="count" @update-count="updateCount" />
</div>
</template>
ライフサイクルフック
基本的にon~でラップするようになった(インポートする必要はない)
Vue2でのbeforeDestroy
, destroyed
はそれぞれVue3でbeforeUnmount
, unmounted
に変更されている(使ったことないけど)
また、beforeCreate
, created
は直接<script setup>
内に処理を書くようになっているので注意
Options API setup
内のフックbeforeCreate 不要* created 不要* beforeMount onBeforeMount mounted onMounted beforeUpdate onBeforeUpdate updated onUpdated beforeUnmount onBeforeUnmount unmounted onUnmounted errorCaptured onErrorCaptured renderTracked onRenderTracked renderTriggered onRenderTriggered activated onActivated deactivated onDeactivated
表の引用元:
Vue2 + Options APIでの書き方
created() {
console.log('created');
},
mounted() {
console.log('mounted');
}
Vue3 + <script setup>での書き方
console.log('created');
onMounted(() => {
console.log('mounted');
});
watch
Vue3から通常のwatch
に加え、watchEffect
が追加された
違いは以下の通り
watch | watchEffect | |
---|---|---|
監視対象の指定 | 明示的に記述 | 自動(関数内で使用されたリアクティブな値を監視) |
変更前後の値 | 取得可能 | 取得不可 |
定義時の実行 | 実行されない | 実行される |
参考:
Vue2 + Options APIでの書き方
// ~~~~略~~~~
data() {
return {
count: 0,
}
},
watch: {
count(newValue, oldValue) {
console.log(newValue, oldValue);
}
}
Vue3 + <script setup>での書き方
import { ref, watch, watchEffect } from 'vue';
const count = ref(0);
const count2 = ref(0);
watch(count, (newValue, oldValue) => {
console.log('count newValue: ' + newValue);
console.log('count oldValue: ' + oldValue);
});
watchEffect(() => {
// count2が更新された場合は実行されない
console.log('count: ' + count.value);
});
$refs
<template>
での記述は変わらないが、ref
でラップした同名の変数に格納してから参照するようになった
Vue2 + Options APIでの書き方
<template>
<p ref="test">test component</p>
</template>
<script>
export default {
mounted() {
// <p>test component</p>
console.log(this.$refs.test);
},
}
</script>
Vue3 + <script setup>での書き方
<script setup>
import { ref } from 'vue';
// 初期値はnullでよい
const test = ref(null);
onMounted(() => {
// <p>test component</p>
console.log(test.value);
});
</script>
<template>
<p ref="test">test component</p>
</template>
$el
Vue3でマルチルートノードコンポーネントがサポートされ、コンポーネントのルート要素は1つのみという制限がなくなったため代わりにref
を使うようになった
Vue3 + Options APIでは使用できるが、一貫性を保つためref
の使用が推奨されている
Vue3 + Composition APIおよび<script setup>ではそもそもthisが参照できないため使用不可?
Vue3で$elを使用した場合の挙動(下記引用のGoogle翻訳):
- ルート要素が1つのコンポーネントの場合、
$el
はその要素を指す - テキストルートを持つコンポーネントの場合、
$el
はテキストノードを指す - 複数のルート要素を持つコンポーネントの場合、
$el
はVueがDOM内のコンポーネントの位置を追跡するために使用するプレースホルダDOM要素(テキストノード、またはSSRハイドレーションモードのコメントノード)となる
- For components with a single root element, $el will point to that element.
- For components with text root, $el will point to the text node.
- For components with multiple root nodes, $el will be the placeholder DOM node that Vue uses to keep track of the component's position in the DOM (a text node, or a comment node in SSR hydration mode).
引用元:
おわり
Vueの(個人的に思う)基本的な機能が書けたので、ひとまずここまでにしておく
またどこかで「これって<script setup>だとどう書くんだ…?」っていうのが出てきたら追記するつもり
Discussion