VueJS中TypeError: Cannot read property 'className' of undefined问题求助
解决标签页高亮的TypeError问题及优化方案
嘿,我一眼就看到你代码里的问题啦!咱们先来解决那个报错,再聊聊更符合Vue风格的优化方式~
错误原因分析
你控制台里的TypeError: Cannot read property 'className' of undefined,是因为在第二个for循环里犯了一个小疏忽:
tablinks = document.getElementsByClassName("tablink"); for (i = 0; i < x.length; i++) { // 这里误用了x的长度,x是城市内容容器的集合! tablinks[i].className = tablinks[i].className.replace(" w3-red", ""); }
你遍历的是tablinks(按钮元素),但循环条件却用了x.length(城市内容容器的数量)。如果按钮数量和内容容器数量不一致,循环就会超出tablinks的范围,访问到undefined的元素,自然就触发报错了。
修复现有代码
只需要把第二个循环的条件改成tablinks.length就行,同时建议用classList来操作类名,比直接拼接字符串更可靠:
methods: { openCity: function(evt, cityName) { var i, x, tablinks; x = document.getElementsByClassName("city"); // 隐藏所有城市内容 for (i = 0; i < x.length; i++) { x[i].style.display = "none"; } tablinks = document.getElementsByClassName("tablink"); // 移除所有按钮的高亮类 for (i = 0; i < tablinks.length; i++) { // 这里改成tablinks.length! tablinks[i].classList.remove("w3-red"); } // 显示目标城市内容 document.getElementById(cityName).style.display = "block"; // 给当前点击的按钮添加高亮类 evt.currentTarget.classList.add("w3-red"); } }
修改后循环会正确遍历所有按钮,不会再出现undefined的问题,按钮高亮功能也能正常工作了。
更优雅的Vue响应式方案
其实在Vue里,我们完全可以避免直接操作DOM,用响应式数据来管理活跃状态,代码会更简洁易维护:
1. 定义响应式数据
在组件的data里添加一个activeCity属性,用来记录当前活跃的城市:
data() { return { activeCity: 'London' // 默认选中London } }
2. 修改模板,绑定类和显示状态
直接用Vue的指令绑定按钮的高亮类和内容的显示状态,不需要写onclick和DOM操作:
<div class="w3-bar w3-black"> <button class="w3-bar-item w3-button tablink" :class="{ 'w3-red': activeCity === 'London' }" @click="activeCity = 'London'" > London </button> <button class="w3-bar-item w3-button tablink" :class="{ 'w3-red': activeCity === 'Paris' }" @click="activeCity = 'Paris'" > Paris </button> <button class="w3-bar-item w3-button tablink" :class="{ 'w3-red': activeCity === 'Tokyo' }" @click="activeCity = 'Tokyo'" > Tokyo </button> </div> <div id="London" class="w3-container w3-border city" v-show="activeCity === 'London'"> <h2>London</h2> <p>London is the capital city of England.</p> </div> <div id="Paris" class="w3-container w3-border city" v-show="activeCity === 'Paris'"> <h2>Paris</h2> <p>Paris is the capital of France.</p> </div> <div id="Tokyo" class="w3-container w3-border city" v-show="activeCity === 'Tokyo'"> <h2>Tokyo</h2> <p>Tokyo is the capital of Japan.</p> </div>
这样一来,完全不需要写openCity方法,Vue会自动根据activeCity的变化更新视图,既避免了DOM操作的潜在问题,也更符合Vue的开发理念~
内容的提问来源于stack exchange,提问作者NuzzeSicK
相关产品推荐
相关产品推荐

