When switching between sections I want to toggle between hide / show and scroll the target section into view.
This code works but it takes two clicks instead of one to complete the process: first click toggles visibility and it takes a second click to actually scroll the target element into view. Try here.
Why is that? How to solve?
Furthermore: advice on how to accomplish this without a separate show variable for each section and without having to pass source section ref is also welcome.
Vue.js:
<template>
<section id="1" ref="1" v-show="show1" style="margin-bottom: 500px">
<p>Section 1</p>
<button @click="showScrollInto('1', '2')">Goto section 2</button>
<button @click="showScrollInto('1', '3')">Goto section 3</button>
</section>
<section id="2" ref="2" v-show="show2">
<p>Section 2</p>
<button @click="showScrollInto('2', '1')">Goto home</button>
</section>
<section id="3" ref="3" v-show="show3">
<p>Section 3</p>
<button @click="showScrollInto('3', '1')">Goto home</button>
</section>
</template>
<script>
export default {
name: "App",
data() {
return {
show1: true,
show2: false,
show3: false
}
},
methods: {
showScrollInto(from, to) {
switch(from) {
case "2":
this.show2 = false
break
case "3":
this.show3 = false
break
default:
this.show1 = true
}
switch(to) {
case "2":
this.show2 = true
break
case "3":
this.show3 = true
break
default:
this.show1 = true
}
this.$refs[to].scrollIntoView({ behavior: 'smooth'})
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
section {
height: 400px;
border: solid 1px black;
}
</style>
After you have changed the data controlling visibility, the DOM still needs to update. When you call scrollIntoView()
immediately, there is still no node to scroll to.
You can wait until the update is finished using nextTick()
:
await this.$nextTick()
this.$refs[to].scrollIntoView({ behavior: "smooth" })
or using a callback:
this.$nextTick(() => this.$refs[to].scrollIntoView({ behavior: "smooth" }))
Now the scroll event happens after the update when the element is available.