如何在Vue3中实现类Gmail的收件人列表(带隐藏计数徽章)
Vue3 实现类似Gmail的收件人列表方案
核心思路
通过获取容器与子元素的实际尺寸,动态计算可显示的收件人数量,超出部分隐藏后用徽章统计剩余数量。
步骤实现
1. 基础布局搭建
先完成结构与样式,父容器用flex实现横向排列,收件人项统一样式,徽章默认隐藏:
<template> <div ref="container" class="recipient-container"> <div v-for="(email, index) in visibleEmails" :key="index" class="recipient-item" > {{ email }} </div> <div v-if="hiddenCount > 0" class="badge">+{{ hiddenCount }}</div> </div> </template> <style scoped> .recipient-container { display: flex; flex-wrap: nowrap; overflow: hidden; padding: 4px; border: 1px solid #ddd; border-radius: 4px; } .recipient-item { display: inline-flex; align-items: center; padding: 4px 8px; margin-right: 6px; background: #f1f3f4; border-radius: 16px; font-size: 14px; } .badge { display: inline-flex; align-items: center; padding: 4px 8px; background: #f1f3f4; border-radius: 16px; font-size: 14px; } </style>
2. 动态计算逻辑实现
用Vue3的ref获取DOM元素,在组件挂载和窗口 resize 时执行尺寸计算:
<script setup> import { ref, onMounted, onUnmounted } from 'vue' // 模拟你的邮箱数组 const emails = ref(['user1@example.com', 'user2@example.com', 'user3@example.com', 'user4@example.com', 'user5@example.com']) const container = ref(null) const visibleEmails = ref([]) const hiddenCount = ref(0) let resizeTimer = null // 计算可显示的收件人数量 const calculateVisibleItems = () => { if (!container.value) return const containerWidth = container.value.clientWidth const badge = container.value.querySelector('.badge') const badgeWidth = badge ? badge.offsetWidth + 6 : 0 // 加上徽章的间距 const items = container.value.querySelectorAll('.recipient-item') let totalWidth = 0 let visibleCount = 0 for (let i = 0; i < items.length; i++) { const itemWidth = items[i].offsetWidth + 6 // 加上收件人项的右侧间距 // 预留徽章宽度,避免最后一项与徽章挤压 if (totalWidth + itemWidth + badgeWidth <= containerWidth) { totalWidth += itemWidth visibleCount++ } else { break } } visibleEmails.value = emails.value.slice(0, visibleCount) hiddenCount.value = emails.value.length - visibleCount } onMounted(() => { calculateVisibleItems() // 监听窗口 resize,防抖减少计算次数 window.addEventListener('resize', () => { clearTimeout(resizeTimer) resizeTimer = setTimeout(calculateVisibleItems, 100) }) }) onUnmounted(() => { window.removeEventListener('resize', () => { clearTimeout(resizeTimer) }) }) </script>
3. 动态更新处理
如果收件人是动态添加/删除的,在数据变更后重新执行计算:
// 示例:添加新邮箱的方法 const addEmail = (newEmail) => { emails.value.push(newEmail) // 等待DOM更新后再计算 setTimeout(calculateVisibleItems, 0) }
关键注意点
- 尺寸计算要完整:需把元素的
margin、padding都纳入计算,避免出现显示偏差。 - 防抖优化:窗口 resize 时用防抖减少重复计算,提升页面性能。
- DOM更新时机:动态修改邮箱数组后,要等DOM渲染完成再执行计算,可通过
setTimeout或nextTick实现。
内容的提问来源于stack exchange,提问作者Jean Flavier
相关产品推荐
相关产品推荐

