vue can't querySelector for child component DOM element

Viewed 1249

I cannot search for child component DOM element, my settings are as follows:

pages/Login.vue

<template>
 <section class="login">
    <div v-show="step === 4" class="login__container">
      <Test />
    </div>
  </section>
</template>

<script>
export default {
  data () {
    return {
      step: 1
    }
  },
  async mounted () {
      this.step = 4 
      await this.$nextTick()
      document.querySelector('.test') // NULL
  },
}
</script>

components/Test.vue

<template>
  <div class="test">
    foo
  </div>
</template>

setTimeout of course is not solution. I also try the same on other page, but without success. What am I doing wrong? I guess the problem must be somewhere in the template or project configuration

@edit

i tried to do the same effect on jsfiddle vue template and fresh nuxt project but no problem there

4 Answers

You could try to use ref instead of querySelector to manipulate the component DOM :

<template>
 <section class="login">
    <div v-show="step === 4" class="login__container">
      <Test ref="test"/>
    </div>
  </section>
</template>

<script>
export default {
  data () {
    return {
      step: 1
    }
  },
  mounted () {
      this.step = 4 
   
      let test=this.$refs.test
  },
}
</script>

This kind of code should work properly

parent.vue

<template>
  <div>
    <test ref="parentTest" @hook:mounted="selectChildElement"></test>
  </div>
</template>

<script>
export default {
  methods: {
    selectChildElement() {
      console.log(this.$refs.parentTest.$refs.test)
    },
  },
}
</script>

Test.vue component

<template>
  <div ref="test">foo</div>
</template>

This is because of the way the parent and children components are mounted, as explained here: https://stackoverflow.com/a/44319825/8816585


As Brahim said, it is also better to use $refs in an SPA context, more info available here.

The @hook:mounted trick was taken from this answer and initially found in this dev.to post.

Another way to access child component is emitting event when its ready and created in DOM,

In the child element:

    <template>
      <div ref="test">foo</div>
    </template>
    <script>
    export default {
      mounted() {
        this.$emit('childMounted', this.$refs.test)
      }
    }
    ...

In your parent:

    <template>
     <section class="login">
        <div v-show="step === 4" class="login__container">
          <Test @childMounted="childMounted"/>
        </div>
      </section>
    </template>
    
    <script>
    export default {
      data () {
        return {
          step: 1
        }
      },
      methods: {
       childMounted(childRef) {
         // Try here 
         // childRef: your child component reference
       }
      }
    }
    </script>

As I thought, the problem is with nuxt, namely auto-importing components. I am using automatic component import in the nuxt configuration.

nuxt.config.js

  components: [
    {
      path: '~/components',
      pathPrefix: false,
    },
  ],

This approach apparently breaks something, and only after manually importing the component did it work properly

import Test from '@/components/Test.vue'

export default {
  name: 'LoginPage',
  components: {
    Test
  },

So the nuxt configuration caused the problem. Thank you for all your help.

Related