如何在JavaScript下拉筛选中添加无数据匹配提示选项
解决方案
1. 启用HTML中的无结果提示项
取消HTML中注释的“No Data Found”选项,并添加标识方便JS识别:
<div class="container"> <form class="form"> <div class="form__group"> <label for="country">Countries</label> <select id="country" name="country" data-dropdown> <option value="">Please select a country</option> <!-- 其他国家选项保持不变 --> <option value="Zimbabwe">Zimbabwe</option> <!-- 启用无结果提示项 --> <option value="N-D-F" data-no-result>No Data Found</option> </select> </div> <button type="submit" class="btn">Submit</button> </form> </div>
2. 修改CSS添加提示项样式
在CSS末尾添加专属样式,区分提示项与普通选项:
/* 无结果提示项样式 */ .dropdown__menu_no-result { background-color: #f5f5f5; color: #999; cursor: default; } .dropdown__menu_no-result:hover { background-color: #f5f5f5; }
3. 修改JavaScript逻辑
3.1 创建自定义下拉时区分提示项
修改createCustomDropdown函数中的选项循环逻辑,给提示项添加特殊类并禁用点击事件:
optionsArr.forEach(option => { const item = document.createElement('div'); item.classList.add('dropdown__menu_item'); item.dataset.value = option.value; item.textContent = option.textContent; // 标记无结果提示项并禁用点击 if(option.value === 'N-D-F') { item.classList.add('dropdown__menu_no-result'); item.style.cursor = 'default'; } else { item.addEventListener('click', setSelected.bind(item, selected, dropdown, menu)); } menuItemsWrapper.appendChild(item); }); // 初始化隐藏无结果提示项 const noResultItem = menuItemsWrapper.querySelector('.dropdown__menu_no-result'); if(noResultItem) { noResultItem.style.display = 'none'; }
3.2 修改筛选函数控制提示项显示
更新filterItems函数,添加无结果判断逻辑,控制提示项的显示/隐藏:
function filterItems(itemsArr, menu) { const customOptions = menu.querySelectorAll('.dropdown__menu_items div'); const value = this.value.toLowerCase(); // 筛选时排除无结果提示项 const filteredItems = itemsArr.filter(item => item.value.toLowerCase().includes(value) && item.value !== 'N-D-F'); const indexesArr = filteredItems.map(item => itemsArr.indexOf(item)); itemsArr.forEach(option => { // 跳过无结果提示项的筛选逻辑 if(option.value !== 'N-D-F') { if(!indexesArr.includes(itemsArr.indexOf(option))) { customOptions[itemsArr.indexOf(option)].style.display = 'none'; } else { if(customOptions[itemsArr.indexOf(option)].offsetParent === null) { customOptions[itemsArr.indexOf(option)].style.display = 'block'; } } } }); // 控制无结果提示项的显示/隐藏 const noResultItem = menu.querySelector('.dropdown__menu_no-result'); const hasValidResults = filteredItems.length > 0; if(hasValidResults) { if(noResultItem) noResultItem.style.display = 'none'; } else { if(noResultItem) noResultItem.style.display = 'block'; } }
3.3 修改选中逻辑,重置时隐藏提示项
更新setSelected函数,确保重置下拉状态时隐藏提示项:
function setSelected(selected, dropdown, menu) { const value = this.dataset.value; const label = this.textContent; selected.textContent = label; dropdown.value = value; menu.style.display = 'none'; menu.querySelector('input').value = ''; // 重置时只恢复有效选项的显示 menu.querySelectorAll('div').forEach(div => { if(div.classList.contains('selected')) { div.classList.remove('selected'); } if(!div.classList.contains('dropdown__menu_no-result') && div.offsetParent === null) { div.style.display = 'block'; } }); // 重置时隐藏无结果提示项 const noResultItem = menu.querySelector('.dropdown__menu_no-result'); if(noResultItem) noResultItem.style.display = 'none'; this.classList.add('selected'); }
完整修改后的代码
HTML
<div class="container"> <form class="form"> <div class="form__group"> <label for="country">Countries</label> <select id="country" name="country" data-dropdown> <option value="">Please select a country</option> <option value="Afganistan">Afghanistan</option> <option value="Albania">Albania</option> <option value="Algeria">Algeria</option> <option value="American Samoa">American Samoa</option> <option value="Andorra">Andorra</option> <option value="Angola">Angola</option> <option value="Anguilla">Anguilla</option> <option value="Antigua & Barbuda">Antigua & Barbuda</option> <option value="Argentina">Argentina</option> <option value="Armenia">Armenia</option> <option value="Aruba">Aruba</option> <option value="Australia">Australia</option> <option value="Austria">Austria</option> <option value="Bonaire">Bonaire</option> <option value="Bosnia & Herzegovina">Bosnia & Herzegovina</option> <option value="Botswana">Botswana</option> <option value="Brazil">Brazil</option> <option value="British Indian Ocean Ter">British Indian Ocean Ter</option> <option value="Brunei">Brunei</option> <option value="Bulgaria">Bulgaria</option> <option value="Virgin Islands (USA)">Virgin Islands (USA)</option> <option value="Wake Island">Wake Island</option> <option value="Wallis & Futana Is">Wallis & Futana Is</option> <option value="Yemen">Yemen</option> <option value="Zaire">Zaire</option> <option value="Zambia">Zambia</option> <option value="Zimbabwe">Zimbabwe</option> <option value="N-D-F" data-no-result>No Data Found</option> </select> </div> <button type="submit" class="btn">Submit</button> </form> </div>
CSS
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap'); :root { --primary-color: #009e6c; --border-color: #eee; } * { box-sizing: border-box; margin: 0; } body { font-family: 'Roboto', sans-serif; font-size: 16px; line-height: 1.5; } header { background-color: var(--primary-color); color: #fff; text-align: center; padding: 50px 0; margin-bottom: 50px; } .container { max-width: 600px; margin: 0 auto; padding-bottom: 50px; } .form { border: 1px solid var(--border-color); padding: 40px; } .form__group { margin-bottom: 20px; } .form__group label { display: block; font-size: 14px; margin-bottom: 5px; } .dropdown { position: relative; } .dropdown__selected { display: flex; align-items: center; width: 100%; height: 40px; padding: 0 20px 0 10px; font-size: 14px; border: 1px solid var(--border-color); position: relative; cursor: pointer; transition: box-shadow .3s ease; } .dropdown__selected::after { top: calc(50% - 2px); right: 10px; border: solid transparent; content: ''; height: 0; width: 0; position: absolute; border-top-color:#000; border-width: 4px; margin-left: -4px; } .dropdown__selected:hover { box-shadow: 0 0 5px rgba(0,0,0,0.1); } .dropdown__menu { position: absolute; top: 100%; left: 0; width: 100%; border: 1px solid var(--border-color); border-top: 0; background-color: #fff; z-index: 5; display: none; } .dropdown__menu_items { max-height: 210px; overflow-y: auto; } .dropdown__menu_search { display: block; width: 100%; border: 0; border-bottom: 1px solid var(--border-color); padding: 12px; outline: 0; background-color: #f9f9f9; } .dropdown__menu_item { padding: 10px; border-bottom: 1px solid var(--border-color); font-size: 14px; cursor: pointer; } .dropdown__menu_item:last-child { border-bottom: 0; } .dropdown__menu_item:hover { background-color: var(--border-color); } .dropdown__menu_item.selected, .dropdown__menu_item.selected:hover { background-color: var(--primary-color); color: #fff; } /* 无结果提示项样式 */ .dropdown__menu_no-result { background-color: #f5f5f5; color: #999; cursor: default; } .dropdown__menu_no-result:hover { background-color: #f5f5f5; } .btn { display: inline-flex; align-items: center; padding: 10px 20px; background-color: var(--primary-color); color: #fff; border: 0; outline: 0; cursor: pointer; }
JavaScript
// Get dropdowns and form const dropdowns = document.querySelectorAll('[data-dropdown]'); const form = document.querySelector('form'); // Check if dropdowns exist on page if(dropdowns.length > 0) { // Loop through dropdowns and create custom dropdown for each select element dropdowns.forEach(dropdown => { createCustomDropdown(dropdown); }); } // Check if form element exist on page if(form !== null) { // When form is submitted console log the value of the select field form.addEventListener('submit', (e) => { e.preventDefault(); console.log('Selected country:', form.querySelector('[name="country"]').value); }); } // Create custom dropdown function createCustomDropdown(dropdown) { // Get all options and convert them from nodelist to array const options = dropdown.querySelectorAll('option'); const optionsArr = Array.prototype.slice.call(options); // Create custom dropdown element and add class dropdown to it // Insert it in the DOM after the select field const customDropdown = document.createElement('div'); customDropdown.classList.add('dropdown'); dropdown.insertAdjacentElement('afterend', customDropdown); // Create element for selected option // Add class to this element, text from the first option in select field and append it to custom dropdown const selected = document.createElement('div'); selected.classList.add('dropdown__selected'); selected.textContent = optionsArr[0].textContent; customDropdown.appendChild(selected); // Create element for dropdown menu, add class to it and append it to custom dropdown // Add click event to selected element to toggle dropdown menu const menu = document.createElement('div'); menu.classList.add('dropdown__menu'); customDropdown.appendChild(menu); selected.addEventListener('click', toggleDropdown.bind(menu)); // Create serach input element // Add class, type and placeholder to this element and append it to menu element const search = document.createElement('input'); search.placeholder = 'Search...'; search.type = 'text'; search.classList.add('dropdown__menu_search'); menu.appendChild(search); // Create wrapper element for menu items, add class to it and append to menu element const menuItemsWrapper = document.createElement('div'); menuItemsWrapper.classList.add('dropdown__menu_items'); menu.appendChild(menuItemsWrapper); // Loop through all options and create custom option for each option and append it to items wrapper element // Add click event for each custom option to set clicked option as selected option optionsArr.forEach(option => { const item = document.createElement('div'); item.classList.add('dropdown__menu_item'); item.dataset.value = option.value; item.textContent = option.textContent; // 标记无结果提示项并禁用点击 if(option.value === 'N-D-F') { item.classList.add('dropdown__menu_no-result'); item.style.cursor = 'default'; } else { item.addEventListener('click', setSelected.bind(item, selected, dropdown, menu)); } menuItemsWrapper.appendChild(item); }); // Add selected class to first custom option menuItemsWrapper.querySelector('div').classList.add('selected'); // 初始化隐藏无结果提示项 const noResultItem = menuItemsWrapper.querySelector('.dropdown__menu_no-result'); if(noResultItem) { noResultItem.style.display = 'none'; } // Add input event to search input element to filter items // Add click event to document element to close custom dropdown if clicked outside of it // Hide original dropdown(select) search.addEventListener('input', filterItems.bind(search, optionsArr, menu)); document.addEventListener('click', closeIfClickedOutside.bind(customDropdown, menu)); dropdown.style.display = 'none'; } // Toggle dropdown function toggleDropdown() { // Check if dropdown is opened and if it is close it, otherwise open it and focus search input if(this.offsetParent !== null) { this.style.display = 'none'; } else { this.style.display = 'block'; this.querySelector('input').focus(); } } // Set selected option function setSelected(selected, dropdown, menu) { // Get value and label from clicked custom option const value = this.dataset.value; const label = this.textContent; // Change the text on selected element // Change the value on select field selected.textContent = label; dropdown.value = value; // Close the menu // Reset search input value // Remove selected class from previously selected option and show all divs if they were filtered // Add selected class to clicked option menu.style.display = 'none'; menu.querySelector('input').value = ''; menu.querySelectorAll('div').forEach(div => { if(div.classList.contains('selected')) { div.classList.remove('selected'); } // 只恢复有效选项的显示 if(!div.classList.contains('dropdown__menu_no-result') && div.offsetParent === null) { div.style.display = 'block'; } }); // 重置时隐藏无结果提示项 const noResultItem = menu.querySelector('.dropdown__menu_no-result'); if(noResultItem) noResultItem.style.display = 'none'; this.classList.add('selected'); } // Filter items function filterItems(itemsArr, menu) { // Get all custom options // Get the value of search input and convert it to all lowercase characters // Get filtered items // Get the indexes of filtered items const customOptions = menu.querySelectorAll('.dropdown__menu_items div'); const value = this.value.toLowerCase(); // 筛选时排除无结果提示项 const filteredItems = itemsArr.filter(item => item.value.toLowerCase().includes(value) && item.value !== 'N-D-F'); const indexesArr = filteredItems.map(item => itemsArr.indexOf(item)); // Check if option is not inside indexes array and hide it and if it is inside indexes array and it is hidden show it itemsArr.forEach(option => { // 跳过无结果提示项的筛选逻辑 if(option.value !== 'N-D-F') { if(!indexesArr.includes(itemsArr.indexOf(option))) { customOptions[itemsArr.indexOf(option)].style.display = 'none'; } else { if(customOptions[itemsArr.indexOf(option)].offsetParent ===
相关产品推荐
相关产品推荐

