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);
      }
    }
},