📗
Vue3でTabulatorを動的にマウントしたい
まだ勉強を始めたばかりなので何か変なところがあれば教えてください
やりたいことと現状
- TabulatorをVue3で使う
- ドキュメントを見るとComponentは無く、refから直接マウントする感じ
- Vuetify(beta)の
v-dialog
の中でTabulatorを使いたい(初期は非表示) - とりあえず
mounted
の中でTabulatorをマウントするとエラーが出る
script setup lang="ts"
import { ref, onMounted } from "vue";
import { TabulatorFull as Tabulator } from "tabulator-tables";
const isShow = ref(false);
const table = ref<HTMLElement>();
const tabulator = ref<Tabulator>();
onMounted(() => {
tabulator.value = new Tabulator(table.value!); //ダメ
});
template
<v-btn @click="isShow = true">開く</v-btn>
<v-dialog v-model="isShow">
<v-card>
<v-card-item>
<div ref="table"></div>
</v-card-item>
</v-card>
</v-dialog>
マウントされた時点でdivは居ないので、Tabulatorを割り当てできない(そりゃそうだ)
試したこと
v-show
を使う(ダメ)
v-show
を使って、Componentのマウント時にtableが居るけど、見えてないという状態を作る作戦。
v-dialog
がv-show
で可視をコントロール出来ないっぽいのでダメでした。
ちなみに普通のComponentならできました。v-show
が使えるならこれが楽かもしれません。
マウント用のメソッドを作る
大人しくメソッドを作り、その中でTabulatorをマウントする。
script setup lang="ts"
import { ref, nextTick } from "vue";
import { TabulatorFull as Tabulator } from "tabulator-tables";
const isShow = ref(false);
const table = ref<HTMLElement>();
const tabulator = ref<Tabulator>();
const tabulatorMount = async () => {
isShow.value = true;
await nextTick(); // tableが出てくるまで待つ
tabulator.value = new Tabulator(table.value!);
}
template
<v-btn @click="tabulatorMount"></v-btn>
<v-dialog v-model="isShow">
<v-card>
<v-card-item>
<div ref="table">開く</div>
</v-card-item>
</v-card>
</v-dialog>
nextTick
でtableが出るまで待ってから、Tabulatorをマウントしました。(本当はちゃんとtableの存在確認をした方が良いかも)
消すとき
消すときも適切に処理しないとエラーが出ます。
script setup lang="ts"
import { ref, nextTick } from "vue";
import { TabulatorFull as Tabulator } from "tabulator-tables";
const isShow = ref(false);
const table = ref<HTMLElement>();
-const tabulator = ref<Tabulator>();
+const tabulator = ref<Tabulator | null>(); // nullable
const tabulatorMount = async () => {
isShow.value = true;
await nextTick(); // tableが出てくるまで待つ
tabulator.value = new Tabulator(table.value!);
}
+const tabulatorUnMount = () => {
+ tabulator.value = null; // tableを消す前にTabulatorを削除しておく
+ isShow.value = false;
+}
template
<v-btn @click="tabulatorMount">開く</v-btn>
<v-dialog v-model="isShow">
<v-card>
<v-card-item>
<div ref="table"></div>
</v-card-item>
+ <v-card-actions>
+ <v-btn @click="tabulatorUnMount">閉じる</v-btn>
+ </v-card-actions>
</v-card>
</v-dialog>
nullで無理やり削除しているのでちょっと微妙な感じがしますが、とりあえず動きます。
(追記)閉じるボタンの配置がダイアログの外だったので、修正しました
まとめ
- refからマウントするライブラリは、ちゃんとref元のHTMLElementがDOMに出てきた後にマウントする
- 消すときも同様にDOMから無くなる前にアンマウントする
結構面倒くさいのでこれ系統のライブラリは単体でComponentを作った方が良いなぁと思いました。
残された謎
- Tabulatorの
reactiveData
をtrueにして実行すると、削除・インスタンス生成を繰り返す度に重くなって、4回目あたりでフリーズします。もうちょっと追えば原因分かりそうですが、とりあえず無くても動くので、また今度。
Discussion