0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

vueでdomの変更を検知する

Last updated at Posted at 2023-03-09

状況

言語選択モーダルを作っていてselectされている初期値を取得したかったのだが、外部ツールで挟んでいるため、class=selectedが描画後に追加されるので、domを監視して変更があったらそのvalueを取得したかった。
dom入れてwatchしても取れなかった。理由わからず。
template

<li v-for="(lang, index) in languages" :value="lang.code"
    :ref="'lang' + index">

script

        
<script>
  mounted() {
    // 自分でdom変更して検知されるか
    watchEffect(()=>{
      console.log(this.$refs['lang0'])
    })
  },
</script>

解決策

MutationObserverという便利なものがあった。
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver

<template>
    <div>{{selectedLang}}</div>
    <div>
      <ul ref="languageList">
        <li class="languageSwtich" v-for="lang in languages" :value="lang.code">
          <span @click="switchLang(lang.code)">{{ lang.name }}</span>
        </li>
      </ul>
    </div>
</template>

<script>
import { ref, onMounted, reactive } from "vue";

export default {
  setup() {
    const languages = reactive([
      { name: '日本語', code: 'ja' },
      { name: 'English', code: 'en' },
      { name: '中国語', code: 'zh'}
    ])

    const selectedLang = ref('日本語')
    const languageList = ref(null)

    onMouned(()=>{
    const observer = new MutationObserver((mutationsList, observer) => {
      for (let mutation of mutationsList) {
        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
            let code = languageList.value.querySelector('.languageSwitch.selected').attributes['value'] 
            switchLang(code)
        }
      }
    })
    // オプションchildList,subtreeをつけると子要素、孫要素まで検知できる
    observer.observe(languageList.value, { attributes: true, childList: true, subtree: true})
    })
    const switchLang = function (code) => {
        const result = languages
            .filter((item) => item.code === code)
            .map((item) => item.name);
        selectedLang.value = result.length > 0 ? result[0] : null;
    }
    return {
      languages,
      selectedLang,
      languageList,
      switchLang,
    }
  }
}

</script>

感想

なまじ変更の検知はwatchEffectという固定観念があったせいで、無駄に時間がかかってしまった。
chatGPTに大雑把に「vueで取得したDomの中のクラスが書き換わった時にイベントを発火したい時はどうしたらいい?」と聞いたらこいつを教えてくれた、ありがとうGPT。

※追記
コメントを元に修正

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?