Vue2からVue3への移行を進めてきた中で私なりに得てきた必要な書き換え等をまとめてみます。
なおTypeScriptでは私が現在は必須でないためTypeScriptでの書き方は一切触れません。
一回なれてない頃にVue3とTypeScriptを同時に作業して死んだのでTypeScriptはしばらく触りたくないです(涙
あとそこまでVueに精通しているわけじゃないので細かい部分は他の方をご参考に。
また私はVue3はsetup構文以降が標準だと思っているので、Vue3.2以降?を前提としています。
全般的な話
- 大前提として
<script setup>
じゃないVue3を覚える理由ってあるのか?? - 基本的にアロー関数で記述します。
- ライフサイクル系は一般的に使う様なモノはcreated以外は全て
on*****
に変わっています。 - 確証は無いけどscriptを最初に書いて、template、styleと続くのが良い
ということで少しずつ雑にですが見ていきます。
コンポーネント
コンポーネントはVue2ではインポートしてからexport default内にcomponentsブロックを書いてその中に記述する必要がありましたが、Vue3ではインポートするだけでいきなりtemplateに記述してもOKになりました。
import ExComp from "****";
<template>
<div>
<ExComp />
</div>
</template>
...省略
components:{
ExComp,
}
これがVue3だと
<script setup>
import ExComp from "****";
</script>
<template>
<div>
<ExComp />
</div>
</template>
でOKです。
サンプルになってないけど。
data(データオブジェクト・・で良いのか?)
まずは簡単にdataについて
<template>
<div>
<p>{{ abc }}</p>
<p>{{ def }}</p>
</div>
</template>
...省略
data(){
return {
abc:0,
def:"",
};
}
こんな感じの奴です。
script部分は面倒なので省略しています。
<script setup>
import { reactive } from "vue";
const data = reactive({
a:0,
b:"",
});
</script>
<template>
<div>
{{ data.a }}
{{ data.b }}
</div>
</template>
となります。
大きな変更点としてはreactive
をVueからインポートする必要があります。
コード側では今までthis.a
とか書いていた物がdata.a
とかになるだけなのでそれほど大変ではないですが、テンプレート側ではどうしても記述が増えます。
ですが、メソッドなのか変数なのかとかわかりやすくなったりします。
あとsetup構文ではtemplateを後に書くほうが良いみたいです。
詳しい理由は私にはわかりませんが(汗
method
ここはVue2だとmethodsブロックに書いてましたがVue3では基本的に全てルートに定義します。
Vue2側はわかってると思うので書きません。
const method1 = () => {
console.log("メソッドだよ");
}:
const method1 = ( a , b ) => {
console.log("メソッドだよ");
console.log(a);
console.log(b);
}:
呼び出しもVue2ではthisが必要でしたがVue3では必要ありません。
method1();
テンプレート側では引数がなければ「()」は書きません(これはVue2でも同じ)
<div @click="method1">メソッド呼び出し</div>
created
created(beforeCreate)についてはライフサイクルの一つとしてVue2では特別扱いでしたがVue3では通常のメソッド扱いです。
こだわらずに通常のメソッド名で記述しても大丈夫・・だと思います(多分
普通に定義を並べて最初に実行すればそれがcreatedってな感じでしょうか。
<script setup>
const created = () =>{
console.log("created");
}
...その他のメソッド定義
created();//最初に呼び出している
</script>
って感じでscript内の定義後に書けば実行されますので特別扱いの必要がなくなった感じですね。
mounted
mounted
についてはimport { onMounted } from "vue";
でインポートする必要があり、少し名称が変わります。
<script setup>
import { onMounted } from "vue";
const onMounted(()=>{
console.log("mounted");
});
</script>
という感じでonMounted
で定義します。
props
続いてpropsです。
setup構文においてはprops
はdefineProps
で定義するだけで使えます。
import
する必要はありません。
<script setup>
const props = defineProps({
p1:0,
p2:"",
});
const aaa = () => {
console.log(props.p1);
console.log(props.p2);
}
</script>
親へのコンポーネント定義はVue2と同じです。
<ComponentExample :p1="変数名" :p2="変数名" />
ただ触った感じで注意しないといけないのはVue2は型がいい加減なので大丈夫ですが、Vue3はTypeScriptを使っていない場合でもある程度の型をチェックします。
ですので今回で言うprops内のp1、p2で、この例では問題ないのですが、配列だったりオブジェクトを受け取る予定で違った型が来るとワーニングを吐きまくります。
Vue2では全て[]
で済ませてる場合もあったと思いますが、Vue3においてはprpps定義時になるべく[]
の配列なのか{}
のオブジェクトなのか程度の型合わせはしましょう。
emits
私の中で移行で苦労したものの一つがemitsです。
propsと同じでdefineEmits
で定義して、importする必要はありません。
子から書きますが・・
<script setup>
const data = reactive({
a1:0,
a2:1,
a3:2,
});
const emits = defineEmits({
["emit1","emit2"]
});
const test1 = () => {
emits("emit1",[data.a1 , data.a2]);
}
const test2 = () => {
emits("emit2",data.a3);
}
</script>
という感じで定義します。
ちょっとわかりにくいですがemitsと言う名前で「emit1」「emit2」を定義しています。
例ではコンポーネント等からtestメソッドが呼び出されたとして、メソッド内で親のemit1のイベントを発火します。
その際にemit1にはa1 a2
の様に複数の変数を配列で渡します。
test2の場合であれば、親のemit2を発火してa3
単発の変数を渡している・・といった感じです。
一応受け取り側として簡略して親側も書いておくと・・
...省略
const method1 = (args) => {
let [a1 , a2] = args;
console.log(a1);
console.log(a2);
}
const method2 = (a3) => {
console.log(a3);
}
...省略
<ExampleComponent @emit1="method1" @emit2="method2" />
簡単に書きました。
子でemit1を発火するとコンポーネントの@emit1
が発火するのでmethod1
が呼び出されます。
その際に子側から変数も渡されているのでmethodで受け取るように処理を書きます。
例ではmethod1は複数の変数が渡されてくるのでスプレッド構文で受け取って処理しています。
対してmethod2は変数が一個なのでそのまま受け取っています。
computed
例ではwatchでもmethodでも同じ処理が出来ます。
例としては最悪ですがcomputed自体が何者か?はここで説明するものではないのでいろんな記事を参考にしてください。
importが必要です。
<script setup>
import { reactive , computed } from "vue";
const data = reactive({
kazu:5,
tanka:20,
});
...省略
const shoukei = computed(()=>{
return data.kazu * data.tanka;
});
</script>
<template>
<p>個数 {{ data.kazu }}</p>
<p>単価 {{ data.tanka }}</p>
<hr />
<p>小計 {{ shoukei }}</p>
</template>
って感じでどうでしょう。
例としては最悪ですがまぁ数や単価が変わると自動的に小計は変わるよって感じです。
watch
watchについてはVue3になってから「watch effect」という物も存在しますが、Vue2からの移行であれば関係ないので興味がある方は自分で調べてください(汗
watch:{
watch_a: function(newVal, oldVal) {
console.log(newVal);
console.log(oldVal);
}
}
一番ベーシックなVue2でのwatchです。
watch_aの変化を検知するとここへ飛んできます。
その際にnewVal
に今回入ってきた新しい値が、oldVal
には今まで入っていた値が入ります。
これによって今まで入ってた値によって処理を振り分けたりする事ができます。
簡単な例としては初回だとoldValには何も入ってないから前回の保存処理を行わない・・とか。
初期処理を行う・・とか。
Vue3ではimportしてcomputed等と同じ様に使用します。
import { reactive , watch } from "vue";
const data = reactive({
watch_a:0,
});
watch(()=> data.watch_a , (newVal , oldVal) => {
console.log(newVal);
console.log(oldVal);
},
{
immediate: true,
deep: true
}
本来は変数がreactiveかどうかで書き方が変わったりしますが、一番アローが多くなる面倒なこの書き方を覚えておけば良いかと。
アローで記述してないと変数の検知が行われなかったりします(propsの値等)
Vue2ではhandlerで記述する時の様なイメージでしょうか。
いずれにしてもnewVal、oldValは同じ様に入ってきますので{}
内は同じ様に書けば大丈夫です。
immediateやdeepはこの場合は必要ありませんが、書き方としてこうやって書けるっていう意味でサンプルとして書いてあります。
子コンポーネントから親コンポーネントのイベント発火
これは先程のemitsになります。
そちらを参考にしてください。
親コンポーネントから子コンポーネントのイベント発火
すみません、勉強不足でなんと言うのかわからなかったのでそのまま日本語です。
ref
を使用します。
<script setup>
import { ref } from "vue";
...省略
const example_ref = ref();
//ここで実際に呼び出す
example_ref.value.exMethods(aaa);
</script>
<template>
<ExComp ref="example_ref" />
</template>
呼び出したいメソッドがあるコンポーネントにrefで名前を付ける(参照できるようにする
その定義したrefに.valueを付けて、その後ろに呼び出すメソッドを記述
当然ですが子に存在するメソッド名を書いてください。
//子は普通にイベントを書く
const exMethods = (aaa) => {
//コードを普通に書く
}
呼び出されるメソッドを普通に書きます。
公開するような特別な記述は必要ありません。
あとがき
Vue2からVue3へ移りたいけど書き方が変わっててわからんとか、どう書いたら良いか?とかで悩んでる人はまだまだいると思います。
私はLaravel+Vueで最近モノを作っててViteを使いたかったけど実質Laravel9とVue3でないとあまり意味ないのではないか?と思い立ち、一気に作業しました。
PHP7のサポートを考えてもそろそろ色々環境を変化させる時かな?って思い立ちましたので。
Vueが2だろうが3だろうが、Laravel側には関係ないのでとりあえずVue側だけで今のところ思いついたモノを書いています。
自分で思い立てば順次追加していこうかと思いますが気力が続くか・・
記述ミス等ございましたが優しくご指摘いただけると幸いです。
メンタル強くないので。