vuejsの気になったところ
watcherの注意点
wacherの中ではthis
を使えない。なるべくcomputedを使う。
watch: {
counter() {
const vm = this;
setTimeout(() => {
vm.counter = 0;
}, 3000);
},
},
v-onディレクティブでの注意点
<!-- method event handler。vue側がいい感じに解釈 -->
<button @click="countUp">+1</button>
<!-- javascript式 -->
<button @click="countUp()">+1</button>
v-showの特徴
- display: noneのcssがかかる
- 全てdomに追加されるため初期描画が遅い
- 要素を削除せずにcssをかけるだけなので描画の切り替えが早い
- elseがない
v-forの特徴
- 要素の変更が最小限になるようになるべく再利用する
- 予期しないバグを生む可能性があるので, key属性をつける
仮想ノード
createElemet
で作られているのは仮想DOMを作るための仮想ノードである。いわゆるDocument Object Modelではなくjavascriptのオブジェクトである。
new Vue({
data: {
name: "tak",
},
render(createElement) {
return createElement("h1", "hello, " + this.name)
}
}).$mount("#app3");
仮想DOM
DOMの変更を高速に反映するための仕組み。DOMを直接変更するには時間がかかるので, 仮想DOMを変更し前の仮想DOMとの差分を反映して高速に描画する。
Babel
JavaScriptのコードを新しい書き方から古い書き方へと変換するツール
Webpack
webpackは、モジュールを束ねるツールです。
モジュールとは、プログラム内のJavaScriptファイル(以下:jsファイル)やsassファイルなどのことです。webpackを使うことで、複数のjsファイルをひとつのjsファイルにまとめたり、複数のsassファイルをひとつのsassファイルにしたりできます。
キャメルケースとケバブケース
親から子にpropsを渡すときはケバブケース。html内で属性を定義するから。
子が親からpropsを受け取るときはキャメルケース。jsとして扱うから。
子が$emitを使ってカスタムイベントを作成するときはケバブケース。js内ではただの文字列であり, 親は属性名としてhtml内でイベントを受け取るからである。
propsで配列やオブジェクトを渡した場合, 子が親のデータを書き換えられる
ここは割とバグを生みそうな点。NumberやStringはプリミティブ型なのに対してこれらはオブジェクト型で参照渡しになっているからである。
slotのstyleは親が優先される
slotの内容を定義しているcomponent内で完結していてわかりやすいためなのかなと思っている。
v-modelをコンポーネントに対して使う
これはなんか忘れそう感があったので書いておく
<EventTitle v-model="eventData.title"></EventTitle>
// 以下と一緒
<EventTitle :value="eventData.title" @input="eventData.title = $event"></EventTitle>
受け取る側は以下の感じでemitを使う
<template>
<div>
<label for="title">タイトル</label>
<input id="title" type="text" :value="value" @input="$emit('input', $event.target.value)">
<pre>{{ value }}</pre>
</div>
</template>
<script>
export default {
props: ["value"]
};
</script>
computedとfilterの違い
methodは親ノードに変更があるたびに発火してしまい, computedは子ノードに変更がない限り発火されなかったが同じような違いがfilterとcomputedにもある。つまりfilterは親ノードに変更があるたびに発火する。
よって, パフォーマンスを考えるならfilterを使わずに全てcomputedで書いた方がいい。ただ書いていると冗長になるので, 場合に応じてfilterを使う。
global mixinはプロジェクトを荒らす
ヘッダの通り。全てのコンポーネント生成時に挿入されるのでパフォーマンスが悪くなる。プラグインを作る時などに使う。
複数の要素を切り替えるトランジションの注意点
v-show
は使えない。v-if
を使う。key
属性をつける。vueはタグが切り替わったときにtransitionを適用するという仕組みなので, 同じタグで区別がつかない場合はtransitionを適用せずにタグの中身だけが書き換わる
transitionの@enterと@leaveのdone引数に関する注意点
jsのアニメーションとcssのアニメーションは共存できる。よって片方のアニメーションが終わったとしてももう片方のアニメーションが動き続けるのがデフォルト。しかし, @enterや@leaveでdoneを使うとcssのアニメーションは終了する。
cssアニメーションがない場合はdoneを必ずつけなければならない。
@leaveCancelledの注意点
@leaveCancelled自体は消えるアニメーションがキャンセルされた時に実行されるもの。
これはv-show属性の要素がある場合にのみ実行される。
v-moveの注意点
.fade-move {
transition: transform 1s;
}
のように書けばtransition-group
に要素が追加されるときにもアニメーションを適用することができるが, 要素を削除するときのカクツキをなくすには
.fade-leave-active {
transition: opacity 1s;
position: absolute;
width: 200px;
}
のように設定しなければならない。
transitionを再利用するときはコンポーネントを使用する
コンポーネントを定義してslotを使うのが定石らしい
transitionが適応されている時のスクロールの振る舞いを非同期実行する
応用オブ応用
以下App.js
<template>
<div style="width: 700px; margin: auto; padding-top: 50px;">
<router-view name="header"></router-view>
<transition name="fade" mode="out-in" @before-enter="beforeEnter">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
methods: {
beforeEnter() {
this.$root.$emit("triggerScroll");
}
}
};
以下main.js
scrollBehavior(to, from, savedPosition) {
return new Promise(resolve => {
this.app.$root.$once("triggerScroll", () => {
let position = { x: 0, y: 0 };
if (savedPosition) {
position = savedPosition;
}
if (to.hash) {
position = { selector: to.hash, offset: { x: 0, y: 100 } };
}
resolve(position);
});
});
}
v-modelをVuexで使う場合
computedの要素にオブジェクトを置いてそこにget()
とset()
を定義できる
computed: {
message: {
get() {
return this.$store.getters.message;
},
set(value) {
this.$store.dispatch("updateMessage", value);
}
}
},