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:
- 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() {
...
}
}
- If you really want to
document.querySelector()
insetup()
, you can useonMounted
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>
- 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>