問題点
掲題のとおりです。
解消方法がわかりましたらご教示ください。
エラーメッセージ
[Vue warn]: Error in mounted hook: "TypeError: Cannot read properties of undefined (reading 'focus')"
該当のソースコード
index.html
1<script src="https://cdn.jsdelivr.net/npm/vue@2.7.11/dist/vue.js"></script> 2<script src="https://unpkg.com/http-vue-loader"></script> 3<div id="app"> 4 <test2 /> 5</div> 6<script> 7const app = new Vue({ 8 el: "#app", 9 components: { 10 test2: httpVueLoader('./test2.vue') 11 }, 12}) 13</script>
test1.vue
1<template> 2 <div><slot /></div> 3</template>
test2.vue
1<template> 2 <test1><input type="text" ref="name" /></test1> 3</template> 4<script> 5module.exports = { 6 mounted() { 7 this.$refs.name.focus() 8 }, 9 components: { 10 test1: httpVueLoader('./test1.vue') 11 }, 12} 13</script>
試したこと
次のソースコードでは正常にフォーカスを設定できることを確認しました。
例1(http-vue-loaderを使わないネストしたコンポーネント)
index.html
1<script src="https://cdn.jsdelivr.net/npm/vue@2.7.11/dist/vue.js"></script> 2<div id="app"> 3 <test2 /> 4</div> 5<script> 6Vue.component('test1', { 7 template: '<div><slot /></div>', 8}) 9Vue.component('test2', { 10 template: '<test1><input type="text" ref="name" /></test1>', 11 mounted() { 12 this.$refs.name.focus() 13 }, 14}) 15const app = new Vue({ 16 el: "#app", 17}) 18</script>
例2(http-vue-loaderを使うネストしないコンポーネント)
index.html
1<script src="https://cdn.jsdelivr.net/npm/vue@2.7.11/dist/vue.js"></script> 2<script src="https://unpkg.com/http-vue-loader"></script> 3<div id="app"> 4 <test /> 5</div> 6<script> 7const app = new Vue({ 8 el: "#app", 9 components: { 10 test: httpVueLoader('./test.vue') 11 }, 12}) 13</script>
test.vue
1<template> 2 <input type="text" ref="name" /> 3</template> 4<script> 5module.exports = { 6 mounted() { 7 this.$refs.name.focus() 8 }, 9} 10</script>
補足情報(FW/ツールのバージョンなど)
Windows10 Pro
Docker 20.10.20
Apache 2.4.54
Chrome 108.0.5359.126
暫定的な回避方法が見つかったのでコメントしておきます。
親コンポーネントの mounted() 実行時に子コンポーネントがマウント済みであるとは保証されていないのが原因のようです。
問題のプログラムでは $refs で子コンポーネントを参照しているわけではありませんが、子コンポーネントがマウントされるまでは $refs も設定されないのではないかと思われます。
◇index.html の <script> に追加
let globalResolve = null
◇test2.vue の mounted() を変更
mounted() {
new Promise((resolve) => {
globalResolve = resolve
}).then(() => {
globalResolve = null
this.$refs.name.focus()
})
},
◇test1.vue に<script> を追加
<script>
module.exports = {
mounted() {
if (globalResolve) globalResolve()
},
}
</script>
なお、公式マニュアルでは $nextTick() を使うことができると書かれていましたが、次のコードでは解消せず、同じエラーになりました。
this.$nextTick(function () { this.$refs.name.focus() })
一応解消はしましたが、グローバル変数を使うのが気に入らないのと、単にフォーカスを設定するために書くコードとしては複雑すぎるのとで、あくまでも暫定的な回避方法と考えています。
よりよい解決方法がありましたらご回答ください。
逆に子コンポーネントより先に親コンポーネントがマウントされると保証されているわけでもないと思うので、上の回避方法ではダメですね…
偶然うまく動作しただけで潜在的な不具合の原因になりそうです。
回答1件