原生js实现类目选择器
实现思路
使用原生JavaScript创建一个类目选择器,涉及DOM操作、事件监听和数据绑定。核心功能包括动态渲染选项、处理用户交互(如点击、悬浮)以及返回选中值。
HTML结构
构建基础的HTML结构,包含一个触发按钮和下拉菜单容器:
<div class="category-selector">
<button class="selector-btn">选择类目</button>
<div class="dropdown-menu hidden">
<ul class="category-list"></ul>
</div>
</div>
CSS样式
添加基础样式控制布局和交互状态:
.category-selector {
position: relative;
display: inline-block;
}
.dropdown-menu {
position: absolute;
border: 1px solid #ddd;
background: white;
width: 200px;
max-height: 300px;
overflow-y: auto;
}
.hidden {
display: none;
}
.category-list li {
padding: 8px 12px;
cursor: pointer;
}
.category-list li:hover {
background-color: #f5f5f5;
}
JavaScript实现
完整逻辑分为数据加载、DOM渲染和事件处理三部分:
初始化选择器
class CategorySelector {
constructor(containerId, options) {
this.container = document.getElementById(containerId);
this.categories = options.data || [];
this.onSelect = options.onSelect || function() {};
this.initDOM();
this.bindEvents();
}
}
渲染列表
initDOM() {
this.container.innerHTML = `
<button class="selector-btn">${this.placeholder || '选择类目'}</button>
<div class="dropdown-menu hidden">
<ul class="category-list"></ul>
</div>
`;
const listContainer = this.container.querySelector('.category-list');
this.categories.forEach(category => {
const li = document.createElement('li');
li.textContent = category.name;
li.dataset.value = category.id;
listContainer.appendChild(li);
});
}
事件绑定
bindEvents() {
const btn = this.container.querySelector('.selector-btn');
const dropdown = this.container.querySelector('.dropdown-menu');
btn.addEventListener('click', () => {
dropdown.classList.toggle('hidden');
});
dropdown.querySelectorAll('li').forEach(item => {
item.addEventListener('click', () => {
btn.textContent = item.textContent;
dropdown.classList.add('hidden');
this.onSelect(item.dataset.value);
});
});
}
使用方法
实例化选择器并配置回调:
const categories = [
{ id: '1', name: '电子产品' },
{ id: '2', name: '家居用品' },
{ id: '3', name: '服装配饰' }
];
new CategorySelector('selector-container', {
data: categories,
onSelect: (selectedId) => {
console.log('选中ID:', selectedId);
}
});
功能扩展
支持多级嵌套分类:
renderNestedCategories(categories, parentEl) {
categories.forEach(category => {
const li = document.createElement('li');
li.innerHTML = `<span>${category.name}</span>`;
if (category.children) {
const ul = document.createElement('ul');
this.renderNestedCategories(category.children, ul);
li.appendChild(ul);
}
parentEl.appendChild(li);
});
}
注意事项
- 动态加载数据时需调用重新渲染方法
- 点击外部区域应关闭下拉框,需添加全局点击监听
- 移动端需考虑触摸事件兼容性
- 大量数据时建议实现虚拟滚动优化性能







