如何用纯JS实现类似Github的@提及用户下拉列表功能
实现方案参考
可选成熟轻量插件
如果不想从零开发,以下几个无框架依赖的纯JS库可以直接满足需求:
tributejs:专门做@提及功能的专用库,支持自定义下拉模板、异步搜索用户、自定义匹配规则,压缩后仅10KB左右,引入即可使用mention.js:超轻量小库,适合简单的@提及场景,配置项少上手门槛极低at.js:早期依赖jQuery的经典@提及库,现在已有纯JS重构版本,功能全面,支持高度自定义下拉样式和交互逻辑
原生JS完整实现方案
不需要插件的话,可以直接用以下代码实现核心功能,可根据自己的需求调整扩展:
HTML结构
<div class="mention-wrapper"> <textarea id="comment-area" placeholder="输入@即可提及用户"></textarea> <ul id="user-dropdown" class="dropdown-hide"></ul> </div>
CSS样式
.mention-wrapper { position: relative; width: 500px; } #comment-area { width: 100%; height: 160px; padding: 8px; box-sizing: border-box; border: 1px solid #d1d5da; border-radius: 6px; } #user-dropdown { position: absolute; top: 32px; left: 8px; margin: 0; padding: 0; list-style: none; width: 220px; border: 1px solid #e1e4e8; border-radius: 6px; background: #fff; box-shadow: 0 8px 24px rgba(149,157,165,0.2); max-height: 300px; overflow-y: auto; z-index: 999; } #user-dropdown li { padding: 8px 12px; cursor: pointer; font-size: 14px; } #user-dropdown li:hover { background-color: #f6f8fa; } .dropdown-hide { display: none; }
JS核心逻辑
// 模拟用户数据,实际使用可替换为接口请求返回的用户列表 const userList = [ {id: 1, nickname: '张三', username: 'zhangsan'}, {id: 2, nickname: '李四', username: 'lisi'}, {id: 3, nickname: '王五', username: 'wangwu'}, {id: 4, nickname: '赵六', username: 'zhaoliu'} ] const textarea = document.getElementById('comment-area') const dropdown = document.getElementById('user-dropdown') let atIndex = -1 // 记录@符号所在的位置 // 监听textarea输入事件 textarea.addEventListener('input', e => { const cursorPos = e.target.selectionStart const content = e.target.value const preCursorContent = content.slice(0, cursorPos) // 匹配光标前最近的@符号,且@后无空格 const matchRes = preCursorContent.match(/@([^\s]*)$/) if (matchRes) { atIndex = preCursorContent.lastIndexOf('@') const searchKey = matchRes[1].toLowerCase() // 过滤匹配的用户 const matchedUsers = userList.filter(user => user.nickname.toLowerCase().includes(searchKey) || user.username.toLowerCase().includes(searchKey) ) renderUserList(matchedUsers) } else { hideDropdown() } }) // 渲染用户下拉列表 function renderUserList(users) { if (users.length === 0) { hideDropdown() return } dropdown.innerHTML = users.map(user => `<li data-username="${user.username}">${user.nickname} (@${user.username})</li>` ).join('') dropdown.classList.remove('dropdown-hide') } // 隐藏下拉列表 function hideDropdown() { dropdown.classList.add('dropdown-hide') atIndex = -1 } // 点击选中用户插入内容 dropdown.addEventListener('click', e => { if (e.target.tagName === 'LI') { const selectedUsername = e.target.dataset.username const originContent = textarea.value // 替换@后的搜索内容为选中的用户名,加空格结束匹配 const newContent = originContent.slice(0, atIndex) + `@${selectedUsername} ` + originContent.slice(textarea.selectionStart) textarea.value = newContent hideDropdown() // 光标定位到插入内容末尾 textarea.focus() const newCursorPos = atIndex + selectedUsername.length + 2 textarea.setSelectionRange(newCursorPos, newCursorPos) } }) // 点击页面其他区域关闭下拉 document.addEventListener('click', e => { if (!textarea.contains(e.target) && !dropdown.contains(e.target)) { hideDropdown() } })
扩展说明
以上代码已经实现了核心的@提及功能,你可以根据需求额外扩展键盘上下键选择用户、异步拉取用户列表、自定义下拉项渲染模板、高亮匹配关键词等功能。
内容的提问来源于stack exchange,提问作者Owaiz Yusufi
相关产品推荐
相关产品推荐

