Vuex自定义下拉框:如何获取选中项的innerText/innerHTML并解决点击事件选中全部routestart的问题
看起来你的问题主要出在事件目标的不确定性和Vuex状态更新的错误逻辑上,咱们一步步来修复:
1. 点击事件的问题:避免依赖$event.target.innerHTML
你当前用$event.target.innerHTML来获取选中的内容,但点击.dropdown__route-container里的子元素(比如<span>或<div>)时,target会变成这些子元素,导致拿到的内容不是你预期的routestart,甚至可能触发意外的行为。更可靠的方式是直接把当前循环的journeyroute对象传给点击方法——既然你已经在v-for里有这个变量了,何必绕弯子呢?
修改模板里的点击事件:
<div class="dropdown__route-container" @click="getRoute(journeyroute)">
2. 修复getRoute方法的逻辑错误
你的getRoute方法里的数组操作完全不对:newJourneyRoutes[i, innerHTML]这行没有任何赋值逻辑,而且看起来你想要的是选中单个路线项,而不是修改原journeyroutes数组。根据你的模板,selectedJourneyroutes是用来展示选中项的,所以应该把选中的journeyroute对象直接提交给Vuex,而不是复制原数组做无效操作。
修改methods里的getRoute:
getRoute(selectedRoute) { // 直接提交选中的路线对象到Vuex this.$store.commit("selectedJourneyroute", selectedRoute); // 关闭下拉框 this.isOpen = false; }
3. 统一Vuex状态的命名与逻辑
注意到你在computed里用了selectedJourneyroute(单数),但commit里又写了updateSelectedJourneyRoutes(复数),这很容易混淆。建议统一命名,比如都用selectedJourneyroute(因为看起来你是选单个项),确保Vuex的mutation是接收单个对象并更新状态:
假设你的Vuex store里的mutation应该是这样的:
mutations: { selectedJourneyroute(state, route) { state.selectedJourneyroute = [route]; // 如果需要展示数组的话,就包成数组;如果单个对象,直接赋值state.selectedJourneyroute = route } }
(这里看你的模板里selectedJourneyroutes是用v-for循环的,所以应该是数组类型,把选中的对象放进数组里更适配模板)
4. 优化模板的选中项展示逻辑
另外,你可以给选中区域的显示加个长度判断,避免空数组时渲染空列表,同时简化下拉框的触发逻辑:
<ul v-show="selectedJourneyroutes.length" class="dropdown__selected" @click="isOpen = !isOpen"> <li v-for="(a, i) in selectedJourneyroutes" :key="i"> {{ a.routestart }} </li> </ul>
完整修复后的组件代码
<template> <div class="dropdown" id="passenger-type"> <div class="dropdown__decoration"> <label class="dropdown__label">Route</label> <ul v-show="selectedJourneyroutes.length" class="dropdown__selected" @click="isOpen = !isOpen"> <li v-for="(a, i) in selectedJourneyroutes" :key="i"> {{ a.routestart }} </li> </ul> <ul class="dropdown__types" v-if="isOpen"> <li class="dropdown__li" v-for="(journeyroute, i) in journeyroutes" :key="journeyroute.route"> <!-- 用唯一标识做key,比index更可靠 --> <div class="dropdown__route-container" @click="getRoute(journeyroute)"> <div class="dropdown__route-detail"> <span>{{ journeyroute.route }}</span> </div> <div class="dropdown__route-detail"> <span>{{ journeyroute.routestart }}</span> </div> <div class="dropdown__route-detail"> <span>{{ journeyroute.routeend }}</span> </div> </div> </li> </ul> </div> </div> </template> <script> export default { data() { return { isOpen: false }; }, computed: { journeyroutes() { // 如果不需要修改原journeyroutes列表,computed不用setter,直接返回即可 return this.$store.state.journeyroutes; }, selectedJourneyroutes: { get() { // 确保返回的是数组,避免v-for报错 return this.$store.state.selectedJourneyroute || []; }, set(value) { this.$store.commit("selectedJourneyroute", value); } }, }, methods: { handleClickOutside(evt) { if (!this.$el.contains(evt.target)) { this.isOpen = false; } }, getRoute(selectedRoute) { // 把选中的路线放进数组,适配模板的v-for this.selectedJourneyroutes = [selectedRoute]; this.isOpen = false; } }, mounted() { document.addEventListener("click", this.handleClickOutside); }, destroyed() { document.removeEventListener("click", this.handleClickOutside); } }; </script>
额外建议
- 尽量避免用index作为
v-for的key,如果你的journeyroute有唯一标识(比如route字段),用它做key更好,能提升渲染性能并避免意外问题。 - 如果
selectedJourneyroutes是用来存储单个选中项,也可以把它改成单个对象而不是数组,这样模板里的v-for就可以去掉,直接渲染selectedJourneyroute.routestart,逻辑更简洁。
内容的提问来源于stack exchange,提问作者Adam Adams

