株式会社クイックのWebサービス開発blog

HAPPYなサービスプランナー・エンジニア・デザイナーのブログです。

Vue.jsの属性継承でハマってHTMLタグのidが重複しちゃった話

こんにちは、システムエンジニアのちーかまです!
エンジニア歴=クイック在籍歴(2年4ヶ月)ということもありビビってブログのネタに技術系を選ばなかった私ですが、 今回は業務中にハマったことをお話できればと思います。

(ちなみに入りたてホヤホヤだった頃の記事はこちら!) aimstogeek.hatenablog.com

問題となった事象

それはとある入力フォームの動作確認をしていたときのことでした。
期待する動きは
「idを元にinputタグを取得し、入力フォームが画面上部に表示されるようスクロールしてフォーカスを当てる」
だったのですが、スクロールするもののフォーカスが当たらない...

デベロッパーツールで確認したところ、なんと目当てのinputタグ以外にdivタグにも同じidが付与されていることが発覚しました。

<div class="font-set-tooltip-wrapper" id="input-0">
  <input type="text" class="comma-num" maxlength="12" id="input-0">
</div>

コード

該当箇所のコードはこんな感じです。

Form.vue

<InputKingaku :id="`input-${index}`"/>

InputKingaku.vue

<template>
  <div class="font-set-tooltip-wrapper">
    <InputCommaNum v-model="num" v-bind="$attrs" maxlength="12" />
  </div>
</template>
<script>
import InputCommaNum from '../common/InputCommaNum.vue'

InputCommaNum.vue

<template>
  <input class="comma-num" type="text"/>
</template>

原因

タイトルにも採用しているためなんとなく察している方もいるかもしれませんが、原因はVue.jsの属性継承にありました。
Vue.jsで属性の継承をする方法は2つあります。

  1. $attrsを渡してあげる
  2. inheritAttrsをtrueに設定する(デフォルトでtrueに設定)

v3.ja.vuejs.org

これを踏まえて該当のコードの属性継承を整理すると、下記の通りになっていることがわかります。
f:id:aimstogeek:20220304163732j:plain

  • InputKingaku.vueでinheritAttrsがデフォルトのtrueに設定
    →InputKingaku.vueのルート要素であるdivタグに属性が継承される

  • InputKingaku.vueでInputCommaNum.vueに$attrsを渡す
    →InputCommaNum.vueのinputタグに属性が継承される

でdivタグにもinputタグにも同じidが振られていたのです...

ということでdivタグに属性継承されないよう、InputKingaku.vueのinheritAttrsをfalseに設定して無事問題は解決しました。

修正後のInputKingaku.vue

<template>
  <div class="font-set-tooltip-wrapper">
    <InputCommaNum v-model="num" v-bind="$attrs" maxlength="12" />
  </div>
</template>
<script>
import InputCommaNum from '../common/InputCommaNum.vue'
export default {
  inheritAttrs: false,
}

最後に

コンポーネントの構成によっては、$attrsとinheritAttrsを併用するかつ継承する属性の中にidがあるとid重複もできてしまう、というのを身を持って学びました。
今後id重複のチェックを強化しようと思います。

拙い文章でしたが、最後までお読みいただきありがとうございました!



\\『真のユーザーファーストでマーケットを創造する』仲間を募集中です!! // 919.jp