Angular12中同级组件如何互相监听事件?预订应用结果块展开收起怎么实现
预订应用搜索结果块联动展开功能实现方案
核心逻辑
- 全局仅维护一个
activeBlockId状态变量,用于存储当前处于展开状态的搜索结果块的唯一标识,无展开块时取值为null - 每个搜索结果块的乘客数量输入框绑定触发事件,事件触发时校验乘客数量符合要求后,直接将
activeBlockId更新为当前块的唯一ID,其余块通过判断自身ID与activeBlockId是否匹配,自动控制表单的显示隐藏 - 可额外拓展点击页面非结果块区域时重置
activeBlockId为null的逻辑,实现点击空白收起所有表单的交互
代码实现示例
原生JavaScript实现
// 预设类名规则:搜索结果块统一使用search-result-block类,每个块添加data-block-id自定义属性存储唯一ID // 乘客输入框使用passenger-count-input类,用户信息表单使用user-info-form类,隐藏样式使用hidden类 const resultBlocks = document.querySelectorAll('.search-result-block') let activeBlockId = null resultBlocks.forEach(block => { const passengerInput = block.querySelector('.passenger-count-input') const userForm = block.querySelector('.user-info-form') passengerInput.addEventListener('input', () => { const currentBlockId = block.dataset.blockId const passengerCount = parseInt(passengerInput.value) || 0 // 乘客数不符合要求时收起当前块 if (passengerCount < 1) { userForm.classList.add('hidden') activeBlockId = activeBlockId === currentBlockId ? null : activeBlockId return } // 先收起之前处于展开状态的块 if (activeBlockId && activeBlockId !== currentBlockId) { document.querySelector(`[data-block-id="${activeBlockId}"] .user-info-form`).classList.add('hidden') } // 展开当前块 userForm.classList.remove('hidden') activeBlockId = currentBlockId }) })
配套CSS:
.hidden { display: none; } /* 可选:添加展开收起过渡动画 */ .user-info-form { transition: all 0.3s ease; overflow: hidden; }
React 实现
import { useState } from 'react' function SearchResultList({ resultList }) { const [activeBlockId, setActiveBlockId] = useState(null) return ( <div className="result-list"> {resultList.map(item => ( <div key={item.id} className="search-result-block"> {/* 搜索结果基础展示内容 */} <input type="number" min={1} placeholder="请输入乘客数量" onChange={(e) => { const count = parseInt(e.target.value) || 0 setActiveBlockId(count >= 1 ? item.id : (prev => prev === item.id ? null : prev)) }} /> {/* 仅当前块ID匹配激活ID时展示表单 */} {activeBlockId === item.id && ( <form className="user-info-form"> {/* 乘客信息表单字段 */} </form> )} </div> ))} </div> ) }
Vue 3 实现
<template> <div class="result-list"> <div v-for="item in resultList" :key="item.id" class="search-result-block" > <!-- 搜索结果基础展示内容 --> <input type="number" min="1" placeholder="请输入乘客数量" @input="handlePassengerInput(item.id, $event)" /> <form class="user-info-form" v-show="activeBlockId === item.id" > <!-- 乘客信息表单字段 --> </form> </div> </div> </template> <script setup> import { ref } from 'vue' const resultList = ref([]) // 接口返回的搜索结果数组 const activeBlockId = ref(null) const handlePassengerInput = (blockId, e) => { const count = parseInt(e.target.value) || 0 if (count >= 1) { activeBlockId.value = blockId } else { activeBlockId.value = activeBlockId.value === blockId ? null : activeBlockId.value } } </script>
交互优化建议
- 若用户在已展开的表单中输入了内容,切换收起前可增加二次确认提示,避免用户输入内容意外丢失
- 给表单的展开收起添加CSS过渡动画,提升操作流畅感
- 新增点击页面空白区域自动重置
activeBlockId的逻辑,适配用户常规操作习惯
内容的提问来源于stack exchange,提问作者Takura Chimoyo
相关产品推荐
相关产品推荐

