带有多选和突出显示关键字的自定义下拉选择框(静态)

带有多选和突出显示关键字的自定义下拉选择框:
Custom Dropdown Select Box with Multiple Selection and Highlighting Keywords:
不使用select元素,用div、ul、li、span元素实现带有多选和突出显示关键字的自定义下拉选择框。
完整控件包含三部分:

  1. 第一步用div模拟select选择框,ul+li模拟option选项,并用span标记关键词;
  2. 第二步CSS渲染展示效果;
  3. 第三步用原生JavaScript脚本实现点击选择,多选,取消选择,获取选中项结果(数组);

1,HTML模拟选择框

核心代码如下:

<!-- 自定义下拉选择框 html 开始 -->
<div class="custom-select">
    <div class="selected-options">
        <span class="placeholder">请选择...</span>
    </div>
    <ul class="options-list">
        <li class="option" data-value="option1">选项1 <span class="highlight">关键词</span></li>
        <li class="option" data-value="option2">选项2</li>
        <li class="option" data-value="option3">这个选项3 也有<span class="highlight">关键词</span></li>
        <li class="option" data-value="option4">选项4</li>
    </ul>
</div>
<!-- 自定义下拉选择框 html 结束 -->

搭配上CSS样式渲染就可以看到静态的选择框。接下来还学通过JavaScript脚本实现功能逻辑。

2,JavaScript脚本实现功能逻辑

我们知道JavaScript是浏览器前端脚本语言,要实现网页动态效果是很合适的。根据面向对象编程思想,首先我们得拿到要处理的对象,即HTML标签(DOM元素),例如:

var customSelect = document.querySelector('.custom-select');
var optionsList = document.querySelector('.options-list');
var selectedOptions = document.querySelector('.selected-options');
var options = document.querySelectorAll('.option');

接着我们对标签元素绑定事件驱动,例如:

监听DOMContentLoaded触发事件

DOMContentLoaded 是一个在网页的文档结构(DOM)加载完成后触发的事件,而不需要等待所有的外部资源(如图片、样式表、脚本等)加载完成。这个事件对于执行依赖于DOM解析完成后的JavaScript代码非常有用,因为它允许你尽早地开始执行代码,而不必等待整个页面完全加载。
    在JavaScript中,你可以使用 addEventListener 方法来监听 DOMContentLoaded 事件。以下是一个简单的示例:

// 网页的文档结构(DOM)加载完成后触发的事件
document.addEventListener('DOMContentLoaded', function (event) {
    event.stopPropagation(); // 阻止事件冒泡到外层元素
    console.log('DOM已加载完成!');  
    // 在这里执行你的代码 
}

    在这个示例中,当 DOMContentLoaded 事件触发时,会执行一个匿名函数,该函数在控制台输出一条消息。你可以在这个函数内部执行任何需要在DOM加载完成后运行的JavaScript代码。
    需要注意的是,DOMContentLoaded 事件只会在文档的初始加载时触发一次。如果你希望在页面加载完成后执行某些操作,并且这些操作需要在每次页面加载时都执行,你可能需要考虑使用其他方法,如 load 事件或 jQuery 的 $(document).ready() 方法(如果你在使用jQuery)。
    另外,如果你正在编写一个库或框架,并且需要确保在DOM加载完成之前不执行任何操作,那么监听 DOMContentLoaded 事件可能是一个很好的选择。这样可以确保你的代码在DOM结构可用时立即执行,而不必等待其他资源加载完成。

监听click触发事件

在JavaScript中,click事件是一个常用的鼠标事件,它在用户点击某个元素(例如,按钮、链接、图片等)时触发。你可以使用addEventListener方法来监听click事件,并在事件触发时执行相应的代码。
通过监听click事件,可以实现各种交互效果,例如按钮点击、链接跳转、图片放大等。可以通过addEventListener方法将click事件绑定到指定的元素上,并在事件触发时执行相应的操作。
以下是一个三种常见的简单示例代码,演示了如何使用click事件:

// 选项标签元素绑定click触发事件
document.querySelectorAll('.option').addEventListener('click', function (event) {
    event.stopPropagation(); // 阻止事件冒泡到外层元素
	console.log('选项标签元素被点击了!');
});

// 实时创建的标签元素绑定click触发事件
var span = document.createElement('span');
span.addEventListener('click', function (event) {
    event.stopPropagation(); // 阻止事件冒泡到外层元素
	console.log('实时创建的标签元素被点击了!');
});

// 点击选项以外的地方触发事件
document.addEventListener('click', function (e) {
    e.stopPropagation(); // 阻止事件冒泡到外层元素
    console.log('选项以外的地方被点击了!');
});

需要注意的是,同一个元素可以添加多个同类型的事件监听器,它们会按照添加的顺序依次执行。此外,你可以使用removeEventListener方法来移除之前添加的事件监听器。
这部分更详细可以参考:JavaScript操作addEventListener监听触发事件

数组的遍历、插入、删除操作

在JavaScript中,数组是一种常见的数据结构,可以包含多个元素,并且可以进行遍历、插入和删除等操作。

这部分更详细可以参考:JavaScript操作数组

调整标签元素展示样式

在JavaScript中,classList.toggle 是一个DOM(Document Object Model)元素的方法,用于切换元素的类名。如果元素已经包含指定的类名,则该类名会被移除;如果元素不包含指定的类名,则该类名会被添加。这个方法在动态修改元素的样式时非常有用。

这部分更详细可以参考:JavaScript操作DOM元素的classList

完整代码

完整代码(DropdownSelectBox.html 单个网页文件):

点击查看代码
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="MobileOptimized" content="240">
    <meta name="applicable-device" content="mobile">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no,shrink-to-fit=no">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">

    <meta name="theme-color" content="#3c80d4" media="(prefers-color-scheme: light)">
    <meta name="theme-color" content="#9cc8ff" media="(prefers-color-scheme: dark)">

    <title>带有多选和突出显示关键字的自定义下拉选择框</title>
    <meta name="Description" content="带有多选和突出显示关键字的自定义下拉选择框:Custom Dropdown Select Box with Multiple Selection and Highlighting Keywords">
    <meta name="author" content="熊仔其人">

    <!-- CSS样式 -->
    <style type="text/css">
        /* 自定义下拉选择框 CSS 开始 */
        .custom-select {
            position: relative;
            width: 200px;
            border: 1px solid #ccc;
            border-radius: 5px;
            padding: 1px;
        }

        .selected-options {
            padding: 1px;
            cursor: pointer;
            background-color: #fff;
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
        }

        .selected-options .selectedOptions-icon-cross {
            background-color: #f8f9fa;
            border: 1px solid #ccc;
            border-radius: 5px;
            padding: 1px;
        }

        .selected-options .selectedOptions-icon-cross::after {
            /* content: '\2717'; */
            content: '\2715';
        }

        .placeholder {
            color: #999;
        }

        .options-list {
            position: absolute;
            top: 100%;
            left: 0;
            right: 0;
            border: 1px solid #ccc;
            border-top: none;
            border-radius: 0 0 5px 5px;
            background-color: #fff;
            list-style: none;
            padding: 0;
            margin: 0;
            display: none;
            /* 默认隐藏选项列表 */
        }

        .option {
            padding: 5px;
            cursor: pointer;
        }

        .option:hover {
            background-color: #f2f2f2;
        }

        .option.selected {
            background-color: #e0e0e0;
        }

        .option.selected::after {
            /* content: '\221A'; */
            content: '\2713';
            color: #007bff;
            margin-left: 5px;
        }

        .highlight {
            color: red;
            /* 关键词标红 */
        }

        /* 显示选项列表 */
        .custom-select.active .options-list {
            display: block;
        }
        /* 自定义下拉选择框 CSS 结束 */
    </style>

</head>

<body>
    带有多选和突出显示关键字的自定义下拉选择框:
    Custom Dropdown Select Box with Multiple Selection and Highlighting Keywords:
    <hr />
    
    <!-- 自定义下拉选择框 html 开始 -->
    <div class="custom-select">
        <div class="selected-options">
            <span class="placeholder">请选择...</span>
        </div>
        <ul class="options-list">
            <li class="option" data-value="option1">选项1 <span class="highlight">关键词</span></li>
            <li class="option" data-value="option2">选项2</li>
            <li class="option" data-value="option3">这个选项3 也有<span class="highlight">关键词</span></li>
            <li class="option" data-value="option4">选项4</li>
        </ul>
    </div>
    <!-- 自定义下拉选择框 html 结束 -->

    <!-- 自定义下拉选择框 JS脚本 开始 -->
    <script>
        document.addEventListener('DOMContentLoaded', function (event) {
            event.stopPropagation(); // 阻止事件冒泡到外层元素
            var customSelect = document.querySelector('.custom-select');
            var optionsList = document.querySelector('.options-list');
            var selectedOptions = document.querySelector('.selected-options');
            var options = document.querySelectorAll('.option');

            // 显示/隐藏选项列表  
            selectedOptions.addEventListener('click', function (event) {
                event.stopPropagation(); // 阻止事件冒泡到外层元素
                customSelect.classList.toggle('active');
            });

            // 选项点击事件  
            options.forEach(function (option) {
                option.addEventListener('click', function (event) {
                    event.stopPropagation(); // 阻止事件冒泡到外层元素
                    var isSelected = this.classList.contains('selected');
                    this.classList.toggle('selected', !isSelected);

                    // 更新已选项显示  
                    updateSelectedDisplay();
                });
            });

            // 点击选项以外的地方关闭选项列表  
            document.addEventListener('click', function (e) {
                e.stopPropagation(); // 阻止事件冒泡到外层元素
                if (!customSelect.contains(e.target)) {
                    customSelect.classList.remove('active');
                }
            });

            // 更新已选项的显示  
            function updateSelectedDisplay() {
                var selectedItems = [];
                options.forEach(function (option) {
                    if (option.classList.contains('selected')) {
                        selectedItems.push({ value: option.getAttribute('data-value'), text: option.textContent.trim() });
                    }
                });

                // 清空并重新填充已选项  
                selectedOptions.innerHTML = '';
                if (selectedItems.length === 0) {
                    selectedOptions.appendChild(document.createTextNode('请选择...'));
                } else {
                    selectedItems.forEach(function (item) {
                        var span = document.createElement('span');
                        span.setAttribute('class', 'selectedOptions-icon-cross');
                        span.setAttribute('data-value', item.value);
                        span.textContent = item.text + ' ';
                        span.addEventListener('click', function (event) {
                            event.stopPropagation(); // 阻止事件冒泡到外层元素
                            var itemValue = this.getAttribute('data-value');
                            options.forEach(function (option) {
                                if (option.getAttribute('data-value') == itemValue) {
                                    option.classList.toggle('selected', false);
                                }
                            });

                            // 更新已选项显示  
                            updateSelectedDisplay();
                        });
                        selectedOptions.appendChild(span);
                    });
                }
            }
        });

        // 获取选中项
        function getSelectedItems() {
            var selectedItems = [];
            var selectedOptions = document.querySelectorAll('.custom-select .selected-options .selectedOptions-icon-cross');
            selectedOptions.forEach(function (option) {
                selectedItems.push({ value: option.getAttribute('data-value'), text: option.textContent.trim() });
            });

            return selectedItems;
        }

    </script>
    <!-- 自定义下拉选择框 JS脚本 结束 -->

</body>

</html>

效果

效果展示:

我这里是将可选择项写固定的,在实际项目中可以改成输入关键词,异步方法去后台查询可供选项的列表,绑定到前端该控件,然后就是正常的在项目中动态地使用了。
请看下一篇: 带有多选和突出显示关键字的自定义下拉选择框(动态) >>

posted @ 2024-12-02 16:02  熊仔其人  阅读(21)  评论(0编辑  收藏  举报