環境
・Vue 3.12.0
・Vuetify 2.4.5
概要
リアクティブなテキストデータをVuetifyのUIコンポーネント(例.v-btn,v-chipなど) でバインディングする際は、v-textディレクティブとmustache構文の挙動に違いがあったので、原因を調べてみた。
発生したエラー
ボタンクリックで表示テキストをリアクティブに変更する際に、コンソールでエラーが出力された。
uncaught domexception: failed to execute 'removechild' on 'node':
the node to be removed is not a child of this node error
①エラーを出力したコード(テキストデータをv-textディレクティブでバインディングしている。)
<template>
...
<v-btn
@click="checked === true ? uncheck() : check()"
v-text="checked === true ? checkedText : uncheckedText"
/>
...
</template>
<script>
...
data(){
return {
checked: true
checkedText: '確認済み',
uncheckText: '未確認'
}
}
...
</scirpt>
<button type="button" class="v-btn v-btn--is-elevated v-btn--has-bg theme--light v-size--default">
確認済み
</button>
②修正後のコード(テキストデータをMustache構文でバインディングしている。)
<template>
...
<v-btn
@click="checked === true ? uncheck() : check()">
{{ checked === true ? checkedText : uncheckedText }}
</v-btn>
...
</template>
<script>
...
data(){
return {
checked: true
checkedText: '確認済み',
uncheckText: '未確認'
}
}
...
</scirpt>
<button type="button" class="v-btn v-btn--is-elevated v-btn--has-bg theme--light v-size--default">
<span class="v-btn__content">確認済み</span>
</button>
エラー内容の確認
MDNでエラー内容を確認してみる。(https://developer.mozilla.org/ja/docs/Web/API/Node/removeChild)
DOM操作時にNodeからchildNodeを消そうとする時に出力されるエラーには2種類存在する模様。
1.そもそもchildNodeが存在しない場合に出力される例外エラー。
<div id="parent"></div>
<script type="text/javascript">
var parent = document.getElementById("parent");
var child = document.getElementById("child");
var removeFail = parent.removeChild(chid);
//Uncaught TypeError: Failed to execute 'removeChild' on 'Node':
//parameter 1 is not of type 'Node'.
// -> childNode自体がページに無い。
</script>
2.DOM上に存在していたが、すでに削除されていた場合に出力される例外エラー。
<div id="parent">
<div id="child">
</div>
</div>
<script type="text/javascript">
var parent = document.getElementById("parent");
var child = document.getElementById("child");
var removeSuccessful = parent.removeChild(chid);
removeFail = parent.removeChild(chid);
//Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be //removed is not a child of this node.
</script>
今回のケースでは、DOMが再描画される際に、前提とされているchildNodeがないので①v-textディレクティブ記法ではエラーが出力されている。今回は、Vueコードからエラーが出ているので、内部でDOMを切り替えているVueかVuetifyの内部で、childNodeがあるかどうかを判定している部分があるのではないかと予想。
Vuetifyで使用しているUIコンポーネントのソースを見てみる.
...
genContent (): VNode {
return this.$createElement('span', {
staticClass: 'v-btn__content',
}, this.$slots.default)
},
...
VuetifyのUIコンポーネントにデータをバインディングする際
1.Mustache記法では、、spanタグでchildNodeが生成される。
2.v-textディレクティブ記法では、Nodeが生成されず,シンプルテキストが描画される。
続いて、VuetifyでリアクティブにNodeを切り替えている部分を見てみる。
...
setTimeout(() => {
animation.classList.remove('v-ripple__animation--in')
animation.classList.add('v-ripple__animation--out')
opacity(animation, 0)
setTimeout(() => {
const ripples = el.getElementsByClassName('v-ripple__animation')
if (ripples.length === 1 && el.dataset.previousPosition) {
el.style.position = el.dataset.previousPosition
delete el.dataset.previousPosition
}
// エラー出力箇所。
animation.parentNode && el.removeChild(animation.parentNode)
}, 300)
}, delay)
...
el.removeChildの箇所で、childNodeを削除しているが、v-text記法ではNodeが生成されないのでここでエラーが出力されている。
まとめ
Vuetifyの他のUIコンポーネントでも、v-text記法でデータをバインディングした際は、Nodeが生成されないので、真偽値で、ボタンを切り替える際にエラーが発生する模様。Vueitfyで、データバインディングする際はMustache記法で書く必要がある。
初めてQiitaに投稿してみました。全く間違っているよという部分等ありましたらご指摘いただけるとありがたいです。
(参考)