如何用JavaScript实现选中用户添加至搜索输入框(仿Gmail样式)
实现类似Gmail收件人选择的标签式输入功能
核心思路
这种效果并非直接修改输入框的value值,而是用一个容器模拟输入框外观,内部包含已选用户的标签和真实的输入框。用户点击列表项时,创建标签元素插入容器,真实输入框始终留在最后接收新输入,同时支持删除已选标签。
完整实现代码
HTML结构
<!-- 模拟输入框的容器 --> <div class="input-wrapper" id="inputWrapper"> <!-- 存放已选用户的标签 --> <div class="selected-tags" id="selectedTags"></div> <!-- 真实的输入框,用于输入搜索内容 --> <input type="text" class="search-input" id="searchInput" placeholder="输入或选择用户..."> </div> <!-- 用户列表 --> <ul class="user-list" id="userList"> <li data-email="alice@example.com">Alice Smith</li> <li data-email="bob@example.com">Bob Johnson</li> <li data-email="charlie@example.com">Charlie Brown</li> </ul>
CSS样式
.input-wrapper { border: 1px solid #ccc; border-radius: 4px; padding: 6px 8px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; min-height: 32px; width: 400px; } .selected-tags { display: flex; flex-wrap: wrap; gap: 6px; } .tag { background-color: #e0e7ff; color: #3730a3; padding: 4px 8px; border-radius: 4px; display: flex; align-items: center; gap: 4px; font-size: 14px; } .tag .remove-btn { cursor: pointer; font-weight: bold; font-size: 16px; line-height: 1; } .search-input { border: none; outline: none; flex: 1; min-width: 120px; font-size: 14px; } .user-list { list-style: none; padding: 0; margin: 10px 0; border: 1px solid #ccc; border-radius: 4px; width: 400px; } .user-list li { padding: 8px 12px; cursor: pointer; border-bottom: 1px solid #eee; } .user-list li:last-child { border-bottom: none; } .user-list li:hover { background-color: #f3f4f6; }
JavaScript逻辑
// 获取DOM元素 const inputWrapper = document.getElementById('inputWrapper'); const selectedTags = document.getElementById('selectedTags'); const searchInput = document.getElementById('searchInput'); const userList = document.getElementById('userList'); // 给用户列表项绑定点击事件 userList.addEventListener('click', (e) => { if (e.target.tagName === 'LI') { const userName = e.target.textContent; const userEmail = e.target.dataset.email; addUserTag(userName, userEmail); // 清空搜索输入框内容 searchInput.value = ''; } }); // 创建并添加用户标签 function addUserTag(name, email) { // 检查是否已添加该用户,避免重复 const existingTags = Array.from(selectedTags.querySelectorAll('.tag')); const isDuplicate = existingTags.some(tag => tag.dataset.email === email); if (isDuplicate) return; // 创建标签元素 const tag = document.createElement('div'); tag.className = 'tag'; tag.dataset.email = email; // 标签内容:用户名+邮箱+删除按钮 tag.innerHTML = ` <span>${name} (${email})</span> <span class="remove-btn">×</span> `; // 绑定标签删除事件 tag.querySelector('.remove-btn').addEventListener('click', () => { tag.remove(); }); // 将标签插入到输入框前方 selectedTags.appendChild(tag); // 让输入框重新获得焦点 searchInput.focus(); } // 点击容器区域时自动聚焦输入框 inputWrapper.addEventListener('click', () => { searchInput.focus(); }); // 阻止点击标签时触发容器的点击事件,避免焦点跳动 selectedTags.addEventListener('click', (e) => { e.stopPropagation(); });
关键功能说明
- 容器模拟输入框:
.input-wrapper通过边框、内边距模拟输入框样式,内部用Flex布局自动排列标签和真实输入框。 - 标签去重:添加标签前先检查该用户是否已存在,避免重复选择。
- 焦点管理:点击容器空白区域自动聚焦输入框,点击标签时阻止事件冒泡,避免输入框意外失去焦点。
- 删除功能:每个标签自带删除按钮,点击后直接移除对应标签。
内容的提问来源于stack exchange,提问作者Gopikrishnan K
相关产品推荐
相关产品推荐

