当前位置: 首页 > article >正文

原生html+js输入框下拉多选带关闭模块完整案例

 

<!DOCTYPE html>
<html>
<head>
<title>多选下拉框</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.multi-select-container {
position: relative;
width: 300px;
margin: 20px;
font-family: Arial, sans-serif;
}
.multi-select-input {
width: 100%;
min-height: 40px;
padding: 5px;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
display: flex;
flex-wrap: wrap;
gap: 5px;
align-items: center;
}
.multi-select-input:focus {
outline: none;
border-color: #4CAF50;
box-shadow: 0 0 5px rgba(76, 175, 80, 0.2);
}
.selected-item {
display: inline-flex;
align-items: center;
background: #e8f5e9;
border: 1px solid #4CAF50;
border-radius: 3px;
padding: 2px 8px;
margin: 2px;
font-size: 14px;
}
.remove-btn {
margin-left: 5px;
color: #666;
cursor: pointer;
font-size: 14px;
padding: 0 3px;
}
.remove-btn:hover {
color: #f44336;
}
.dropdown-list {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
margin-top: 5px;
max-height: 200px;
overflow-y: auto;
z-index: 1000;
display: none;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.dropdown-item {
padding: 8px 12px;
cursor: pointer;
display: flex;
align-items: center;
}
.dropdown-item:hover {
background-color: #f5f5f5;
}
.dropdown-item.selected {
background-color: #e8f5e9;
color: #4CAF50;
}
.dropdown-item input[type="checkbox"] {
margin-right: 8px;
}
.limit-message {
color: #f44336;
font-size: 12px;
margin-top: 5px;
display: none;
}
/* 自定义滚动条 */
.dropdown-list::-webkit-scrollbar {
width: 6px;
}
.dropdown-list::-webkit-scrollbar-track {
background: #f1f1f1;
}
.dropdown-list::-webkit-scrollbar-thumb {
background: #888;
border-radius: 3px;
}
.dropdown-list::-webkit-scrollbar-thumb:hover {
background: #555;
}
</style>
</head>
<body>
<div class="multi-select-container">
<div class="multi-select-input" id="selectInput" tabindex="0">
<span class="placeholder">请选择分类...</span>
</div>
<div class="dropdown-list" id="dropdownList"></div>
<div class="limit-message">最多只能选择3个选项</div>
</div>
<script>
class MultiSelect {
constructor(options = {}) {
this.maxSelect = options.maxSelect || 3;
this.container = document.querySelector('.multi-select-container');
this.input = document.getElementById('selectInput');
this.dropdown = document.getElementById('dropdownList');
this.limitMessage = document.querySelector('.limit-message');
this.placeholder = this.input.querySelector('.placeholder');
this.selectedItems = new Set();
// 示例数据
this.items = options.items || [
{ id: 1, name: '技术' },
{ id: 2, name: '设计' },
{ id: 3, name: '产品' },
{ id: 4, name: '运营' },
{ id: 5, name: '市场' },
{ id: 6, name: '销售' },
{ id: 7, name: '客服' },
{ id: 8, name: '人力资源' }
];
this.init();
}
init() {
this.renderDropdown();
this.bindEvents();
}
renderDropdown() {
this.dropdown.innerHTML = this.items.map(item => `
<div class="dropdown-item" data-id="${item.id}">
<input type="checkbox" id="item${item.id}" ${this.selectedItems.has(item.id) ? 'checked' : ''}>
<label for="item${item.id}">${item.name}</label>
</div>
`).join('');
}
updateSelectedDisplay() {
const selectedHtml = Array.from(this.selectedItems).map(id => {
const item = this.items.find(i => i.id === id);
return `
<span class="selected-item" data-id="${id}">
${item.name}
<span class="remove-btn" data-id="${id}">×</span>
</span>
`;
}).join('');
this.input.innerHTML = selectedHtml || '<span class="placeholder">请选择分类...</span>';
}
toggleDropdown(show) {
this.dropdown.style.display = show ? 'block' : 'none';
if (show) {
this.renderDropdown();
}
}
bindEvents() {
// 点击输入框显示下拉列表
this.input.addEventListener('click', () => {
this.toggleDropdown(true);
});
// 点击其他地方关闭下拉列表
document.addEventListener('click', (e) => {
if (!this.container.contains(e.target)) {
this.toggleDropdown(false);
}
});
// 选择项目
this.dropdown.addEventListener('click', (e) => {
const item = e.target.closest('.dropdown-item');
if (!item) return;
const id = parseInt(item.dataset.id);
const checkbox = item.querySelector('input[type="checkbox"]');
if (this.selectedItems.has(id)) {
this.selectedItems.delete(id);
checkbox.checked = false;
} else {
if (this.selectedItems.size >= this.maxSelect) {
this.showLimitMessage();
return;
}
this.selectedItems.add(id);
checkbox.checked = true;
}
this.updateSelectedDisplay();
e.stopPropagation();
});
// 删除已选项
this.input.addEventListener('click', (e) => {
if (e.target.classList.contains('remove-btn')) {
const id = parseInt(e.target.dataset.id);
this.selectedItems.delete(id);
this.updateSelectedDisplay();
this.renderDropdown();
e.stopPropagation();
}
});
}
showLimitMessage() {
this.limitMessage.style.display = 'block';
setTimeout(() => {
this.limitMessage.style.display = 'none';
}, 2000);
}
// 获取选中的值
getSelected() {
return Array.from(this.selectedItems).map(id =>
this.items.find(item => item.id === id)
);
}
}
// 初始化
const multiSelect = new MultiSelect({
maxSelect: 3,
items: [
{ id: 1, name: '技术' },
{ id: 2, name: '设计' },
{ id: 3, name: '产品' },
{ id: 4, name: '运营' },
{ id: 5, name: '市场' },
{ id: 6, name: '销售' },
{ id: 7, name: '客服' },
{ id: 8, name: '人力资源' }
]
});
</script>
</body>
</html>

 


http://www.kler.cn/a/386897.html

相关文章:

  • (干货)Jenkins使用kubernetes插件连接k8s的认证方式
  • ubuntu20.04安装FLIR灰点相机BFS-PGE-16S2C-CS的ROS驱动
  • [CKS] 关闭API凭据自动挂载
  • fastapi 查询参数支持 Pydantic Model:参数校验与配置技巧
  • 【2024最新】math-expression-evaluator 动态计算表达式的使用
  • Rust学习(二):rust基础语法Ⅰ
  • 算力与能量的全分布式在线共享来降低5G网络的用电成本。基于随机对偶次梯度法的多时隙约束耦合问题解耦方法示例;随机对偶次梯度法的在线管理策略
  • Java基础Day-Fifteen
  • 小红书图文矩阵的运营策略与引流技巧解析
  • 兵马未动,粮草先行-InnoDB统计数据是如何收集的
  • Webserver(5.4)项目整体
  • 国产化浪潮下,高科技企业如何选择合适的国产ftp软件方案?
  • 教程:FFmpeg结合GPU实现720p至4K视频转换
  • PySimpleGUI 库 和 pymsql 库
  • 内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪
  • SQLI LABS | Less-36 GET-Bypass mysql_real_escape_string
  • Python 函数专题:可变参数详解
  • Redis(3):持久化
  • 【提高篇】3.1 GPIO(一,基础知识)
  • Doris 游戏数据分析实战,计算留存
  • 寻找存在的路径/寻找图中是否存在路径 C# 并查集
  • 亲测有效:Maven3.8.1使用Tomcat8插件启动项目
  • 《数据治理精选案例集2.0(2024版)》592页PDF(已授权分享)
  • AI大模型如何重塑软件开发流程
  • PostgreSQL 删除数据库
  • 蓝桥杯2022年第十三届省赛真题-求和