tomatoaiu の Tech Blog

プログラミングやツールについてのまとめブログ

Vue.js インスタンスを生成し再描画する時に`v-on`ディレクティブがある場合

motivation

Vueのインスタンスを生成して子コンポーネントを再描画するときに、v-onディレクティブを設定する方法にたどり着くのが大変だったのでメモ。
前回の記事: Vue.js 子コンポーネントを強制的に再描画するいくつかの方法

outline

github.com

prerequisites

versions

  • vue: 2.6.10
  • core-js: 2.6.5

components

子コンポーネントに$emitを配置。イベント名はecho

▼ EmitChild.vue

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">+ 1</button>
    <button @click="emit">emit</button>
  </div>
</template>

<script>
export default {
  name: "EmitChild",
  data() {
    return {
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
    },
    emit() {
      this.$emit("echo", this.count);
    }
  }
};
</script>

solutions

Vueのインスタンスメソッドのvm.$on(event, callback)を追加することで解決できた。

emit-instance

<template>
  <div>
    <button @click="toggle">rerender by emit instance</button>
    <div ref="parent">
      <emit-child @echo="echo"></emit-child>
    </div>
    <p v-if="echo">echo: {{ text }}</p>
  </div>
</template>

<script>
import Vue from "vue";
import EmitChild from "./EmitChild.vue";

export default {
  name: "Key",
  components: {
    EmitChild
  },
  data() {
    return {
      text: ""
    };
  },
  methods: {
    toggle() {
      this.$refs["parent"].textContent = null;
      const ComponentClass = Vue.extend(EmitChild);
      const instance = new ComponentClass();
      instance.$mount();
      instance.$on("echo", e => this.echo(e));
      this.$refs["parent"].appendChild(instance.$el);
    },
    echo(e) {
      this.text = e;
    }
  }
};
</script>

failure

解決策にたどり着くまでの失敗。

propsData

propsにいれてみる。この方法だと親から渡したい値はpropsとして渡るが、イベントの購読はできない。

toggle() {
  this.$refs["parent"].textContent = null;
  const ComponentClass = Vue.extend(EmitChild);
  const instance = new ComponentClass({ propsData: this.echo });
  instance.$mount();
  this.$refs["parent"].appendChild(instance.$el);
},

references

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js

  • 作者:MIO
  • 発売日: 2018/05/29
  • メディア: Kindle版