Home > Software engineering >  How do I use the mounted function in VueJs 3 composition api?
How do I use the mounted function in VueJs 3 composition api?

Time:10-31

I am trying out the composition api in vueJs 3. Unfortunately I don't know how to include my mounted code in the setup(). When I put the code into the setup, the javascript tries to access the not yet rendered DOM. Can anyone tell me how I have to rewrite this?

Option api sytle (works)

<script>
export default {
    name: "NavBar",
    data() {
        return {};
    },
    methods: {},
    mounted() {
        const bm = document.querySelector('#toggle');
        const menu = document.querySelectorAll('nav ul li');
        const overlay = document.querySelector('#overlay');

        // ...
        bm.addEventListener('click', () => {  
            bm.classList.toggle("active");
            overlay.classList.toggle("open");
        })
 
    },
}
</script>
<template>
    <header>
        <div  id="toggle">
          <span ></span>
          <span ></span>
          <span ></span>
        </div>
        <div  id="overlay">
          <nav >
            <ul>
            <li><a href="#home">Home</a></li>
            <!-- ... -->
            </ul>
          </nav>
        </div>      
    </header>    
</template>

CodePudding user response:

  1. First of all, this not a good practice to get a html element via document.querySelector(), see how to bind events in vue3
// bad

<div  id="toggle">...</div>

mounted() {
    const bm = document.querySelector('#toggle');
    bm.addEventListener('click', () => {  
        bm.classList.toggle("active");
        overlay.classList.toggle("open");
    })
}

// good
<div  id="toggle" @click="toggleContainer">...</div>

methods: {
    toggleContainer() {
        ...
    }
}
  1. If you really want to document.querySelector() in setup(), you can use onMounted
import { onMounted } from 'vue';

export default {
    setup() {
        onMounted(() => {
             const bm = document.querySelector('#toggle');
             bm.addEventListener('click', () => {  
                 bm.classList.toggle("active");
                 overlay.classList.toggle("open");
             })
        });
    }
}

// or inside <script setup>

import { onMounted } from 'vue';

onMounted(() => {
   ....
});

But, just as @kissu commented, ref is a better way if you have to handle the html tag directly in vue

<div
   ref="toggler">
   ...
</div>

<script setup>
import { ref, onMounted } from 'vue';

const toggler = ref(null);

onMounted(() => {
    console.log(toggler.value) // <div></div>
});
</script>

  1. But none of the above follow the concept of Vue, which is Vue is driven by data.

Since you seem to create a click event listener which will effect the class in html, here is the Vue way:

<template>
    <header>
        <div
          
          id="toggle"
          :
          @click="toggle">
          <span ></span>
          <span ></span>
          <span ></span>
        </div>
        <div
          
          id="overlay"
          :>
          <nav >
            <ul>
            <li><a href="#home">Home</a></li>
            <!-- ... -->
            </ul>
          </nav>
        </div>      
    </header>    
</template>

<script setup>
import { ref } from 'vue';

const isActiveBm = ref(false);
const isOpenOverlay = ref(false);

const toggle = () => {
    isActiveBm.value = !isActiveBm.value;
    isOpenOverlay.value = !isOpenOverlay.value;
}
</script>
  • Related