Vue.js如何一键切换区块可见性并滚动到目标区块?
Vue切换区块时滚动需两次点击的问题解决及优化方案
问题原因
Vue的响应式DOM更新是异步的。你修改show2/show3这些显示变量后,Vue不会立刻更新页面DOM,而是把DOM更新任务放进异步队列延后执行。这时候直接调用scrollIntoView,目标元素还处于display: none的隐藏状态,滚动操作找不到可滚动的目标元素,所以第一次点击只有显示状态切换,第二次点击时DOM已经完成更新,元素显示出来,滚动才生效。
快速修复方案
把滚动操作放到this.$nextTick()回调里,等待Vue完成DOM更新后再执行滚动:
修改后的showScrollInto方法:
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 } // 等待DOM更新完成后执行滚动 this.$nextTick(() => { this.$refs[to].scrollIntoView({ behavior: 'smooth'}) }) }
优化实现方案(无需单独show变量、无需传递from参数)
用一个activeSection变量记录当前激活的区块ID,所有区块的显示状态都由这个变量控制,不用维护多个独立的show变量,也不用传递来源区块参数:
完整代码示例:
<template> <section id="1" ref="1" v-show="activeSection === '1'" style="margin-bottom: 500px"> <p>Section 1</p> <button @click="switchSection('2')">Goto section 2</button> <button @click="switchSection('3')">Goto section 3</button> </section> <section id="2" ref="2" v-show="activeSection === '2'"> <p>Section 2</p> <button @click="switchSection('1')">Goto home</button> </section> <section id="3" ref="3" v-show="activeSection === '3'"> <p>Section 3</p> <button @click="switchSection('1')">Goto home</button> </section> </template> <script> export default { name: "App", data() { return { activeSection: '1' // 默认激活第一个区块 } }, methods: { switchSection(targetId) { this.activeSection = targetId this.$nextTick(() => { this.$refs[targetId].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>
这个优化方案的优势:
- 只用一个变量维护激活状态,代码更简洁,不易出错
- 方法无需接收来源区块参数,逻辑更清晰
- 扩展性更强,新增区块时只需添加对应的section和切换按钮,无需修改data和方法逻辑
内容的提问来源于stack exchange,提问作者user1837293
相关产品推荐
相关产品推荐

