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

html 复制代码
<!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>
相关推荐
sinat_384241098 分钟前
在有网络连接的机器上打包 electron 及其依赖项,在没有网络连接的机器上安装这些离线包
javascript·arcgis·electron
小牛itbull32 分钟前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i40 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_43 分钟前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium
ZBY520311 小时前
【Vue】 npm install amap-js-api-loader指南
javascript·vue.js·npm
猫爪笔记1 小时前
前端:HTML (学习笔记)【2】
前端·笔记·学习·html
前端拾光者2 小时前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
风尚云网3 小时前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网