質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Q&A

解決済

1回答

664閲覧

Vue2のCDN版でhttp-vue-loaderを使うとネストしたコンポーネントで初期フォーカスを設定できない

gosaro

総合スコア24

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

0グッド

0クリップ

投稿2023/01/16 02:26

問題点

掲題のとおりです。
解消方法がわかりましたらご教示ください。

エラーメッセージ

[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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gosaro

2023/01/17 01:32

暫定的な回避方法が見つかったのでコメントしておきます。 親コンポーネントの 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() }) 一応解消はしましたが、グローバル変数を使うのが気に入らないのと、単にフォーカスを設定するために書くコードとしては複雑すぎるのとで、あくまでも暫定的な回避方法と考えています。 よりよい解決方法がありましたらご回答ください。
gosaro

2023/01/17 07:13

逆に子コンポーネントより先に親コンポーネントがマウントされると保証されているわけでもないと思うので、上の回避方法ではダメですね… 偶然うまく動作しただけで潜在的な不具合の原因になりそうです。
guest

回答1

0

自己解決

自己解決です。
安直ですがポーリングすることにしました。

test2.vue(mounted()のみ抜粋)

1 async mounted() { 2 while (!this.$refs?.name) await new Promise((r) => setTimeout(() => r(), 10)) 3 this.$refs.name.focus() 4 },

投稿2023/01/19 01:55

gosaro

総合スコア24

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問