CSSflex布局列表单个元素点击本行下插入详情独占一行
- 其他
- 2025-09-06 14:18:02

技术栈:Vue2 + javaScript 简介
在实际开发过程中有遇到一个场景:一个list,每行个数固定,点击单个元素后,在当前行与下一行之间插入一行元素详情,便于更直观的查看到对应的数据详情。 这种情形,在移动端比较常见,比如用户列表,点击单个列表 展示详情,可以考虑 flex 布局 + position relative 定位。
实现 思路对于需求重点和实现拆解
列表元素:for 遍历每行固定(3)个元素:flex布局、宽度%详情在该元素下独占一行:for 内元素、position relative 核心代码 mock数据 // list数据 list: [ { id: 1, name: '测试数据1', desc: '测试数据1描述测试数据1描述测试数据1描述测试数据1描述' }, { id: 2, name: '测试数据2', desc: '测试数据2描述测试数据2描述测试数据2描述测试数据2描述' }, { id: 3, name: '测试数据3', desc: '测试数据3描述测试数据3描述测试数据3描述测试数据3描述' }, { id: 4, name: '测试数据4', desc: '测试数据4描述测试数据4描述测试数据4描述测试数据4描述' }, { id: 5, name: '测试数据5', desc: '测试数据5描述测试数据5描述测试数据5描述测试数据5描述' }, { id: 6, name: '测试数据6', desc: '测试数据6描述测试数据6描述测试数据6描述测试数据6描述' }, { id: 7, name: '测试数据7', desc: '测试数据7描述测试数据7描述测试数据7描述测试数据7描述' }, { id: 8, name: '测试数据8', desc: '测试数据8描述测试数据8描述测试数据8描述测试数据8描述' }, { id: 9, name: '测试数据9', desc: '测试数据9描述测试数据9描述测试数据9描述测试数据9描述' }, { id: 10, name: '测试数据10', desc: '测试数据10描述测试数据10描述测试数据10描述测试数据10描述' }, { id: 11, name: '测试数据11', desc: '测试数据11描述测试数据11描述测试数据11描述测试数据11描述' } ], showDetail: false, // 是否显示详情 detail: {}, // 详情数据 DOM结构 <!-- 列表容器 --> <div class="container"> <!-- 单个元素 start--> <div v-for="(item, index) in list" :key="index" class="item-box" @click="toggleEvent(item)"> <div class="item-name">{{ item.name }}</div> <!-- 详情 start --> <div class="item-detail" v-if="showDetail && detail.id == item.id" :style="caculateDetailLeft(index)"> <!-- 气泡三角 --> <div class="top-jian" :style="caculateJianLeft(index)"></div> <!-- 详情描述 --> <div>{{ detail.desc }}</div> </div> <!-- 详情 end --> </div> <!-- 单个元素 end --> </div> CSS 与 动态位移 .container { width: 80vw; // 列表固定宽度 display: flex; gap: 16px; // 元素间距 flex-wrap: wrap; .item-box { // calc((父元素宽度 - 间距*(每行个数-1)) / 每行个数) width: calc((100% - 32px) / 3); .item-detail { width: 80vw; // 列表固定宽度 position: relative; background: #AFF050; .top-jian { width: 20px; height: 20px; position: absolute; background: #AFF050; -webkit-transform: rotate(45deg); transform: rotate(45deg); top: -6px; } } } } caculateDetailLeft(index) { return { // calc(calc(calc(100% + 16px) * ${index%3}) * -1) // calc(-1 * (100% + 间距) * ${index % 每行个数}) left: `calc(-1 * (100% + 16px) * ${index % 3})` } }, caculateJianLeft(index) { return { // calc(calc(calc((100% - 32px) / 3) * ${index%3}) + calc((100% - 32px) / 6)) // calc((100% - 间距*2) * (${index % 每行个数} / 每行个数 + 1 / (每行个数*2))) left: `calc((100% - 32px) * (${index % 3} / 3 + 1 / 6))` } } 效果 完整代码 <template> <div class="container"> <div v-for="(item, index) in list" :key="index" class="item-box" @click="toggleEvent(item)"> <div class="item-name">{{ item.name }}</div> <div class="item-detail" v-if="showDetail && detail.id == item.id" :style="caculateDetailLeft(index)"> <div class="top-jian" :style="caculateJianLeft(index)"></div> <div> {{ detail.desc }} </div> </div> </div> </div> </template> <script> export default { name: 'Test', data() { return { list: [ { id: 1, name: '测试数据1', desc: '测试数据1描述测试数据1描述测试数据1描述测试数据1描述' }, { id: 2, name: '测试数据2', desc: '测试数据2描述测试数据2描述测试数据2描述测试数据2描述' }, { id: 3, name: '测试数据3', desc: '测试数据3描述测试数据3描述测试数据3描述测试数据3描述' }, { id: 4, name: '测试数据4', desc: '测试数据4描述测试数据4描述测试数据4描述测试数据4描述' }, { id: 5, name: '测试数据5', desc: '测试数据5描述测试数据5描述测试数据5描述测试数据5描述' }, { id: 6, name: '测试数据6', desc: '测试数据6描述测试数据6描述测试数据6描述测试数据6描述' }, { id: 7, name: '测试数据7', desc: '测试数据7描述测试数据7描述测试数据7描述测试数据7描述' }, { id: 8, name: '测试数据8', desc: '测试数据8描述测试数据8描述测试数据8描述测试数据8描述' }, { id: 9, name: '测试数据9', desc: '测试数据9描述测试数据9描述测试数据9描述测试数据9描述' }, { id: 10, name: '测试数据10', desc: '测试数据10描述测试数据10描述测试数据10描述测试数据10描述' }, { id: 11, name: '测试数据11', desc: '测试数据11描述测试数据11描述测试数据11描述测试数据11描述' } ], showDetail: false, detail: {}, } }, methods: { toggleEvent(item) { if (item.id == this.detail.id) { this.showDetail = !this.showDetail } else { this.showDetail = true this.detail = { ...item } } }, caculateDetailLeft(index) { return { // calc(calc(calc(100% + 16px) * ${index%3}) * -1) left: `calc(-1 * (100% + 16px) * ${index % 3})` } }, caculateJianLeft(index) { return { // calc(calc(calc((100% - 32px) / 3) * ${index%3}) + calc((100% - 32px) / 6)) left: `calc((100% - 32px) * (${index % 3} / 3 + 1 / 6))` } } } } </script> <style lang="scss" scoped> .container { width: 80vw; display: flex; gap: 16px; flex-wrap: wrap; .item-box { width: calc((100% - 32px) / 3); .item-name { border: 1px solid #ccc; padding: 30px; text-align: center; border-radius: 15px; } .item-detail { width: 80vw; position: relative; background: #AFF050; margin-top: 16px; padding: 30px; border-radius: 15px; .top-jian { width: 20px; height: 20px; position: absolute; background: #AFF050; -webkit-transform: rotate(45deg); transform: rotate(45deg); top: -6px; } } } } </style>CSSflex布局列表单个元素点击本行下插入详情独占一行由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“CSSflex布局列表单个元素点击本行下插入详情独占一行”
下一篇
BMS项目-面试及答疑整理