首页 > 其他分享 >带有多选和突出显示关键字的自定义下拉选择框(动态)

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

时间:2024-12-02 16:45:27浏览次数:4  
标签:function 多选 自定义 text value 关键字 keywords event option

本文是在上一篇的基础上改造成 根据输入关键词动态筛选选项列表,然后实现多项选择并且关键词高亮。
上一篇:带有多选和突出显示关键字的自定义下拉选择框(静态) >>

带有多选和突出显示关键字的自定义下拉选择框:
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脚本实现点击选择,多选,取消选择,获取选中项结果(数组);
  4. 第四步改造成:根据输入关键词动态筛选选项列表。

文本中将多个关键词高亮显示为红色字体

我们常见的搜索引擎都会将检索出来的内容的关键词高亮显示为红色字体,那些一般是后端实现的。我们这里通过前端JavaScript脚本也可以实现:

<!-- 文本中将多个关键词高亮显示为红色字体 开始 -->
<script>
    let text = "这是一段包含多个关键词的文本,例如apple、banana和orange。";
    let keywords = "apple banana orange";
    // let keywords = ["apple", "banana", "orange"]; // 关键词列表,或者空格分隔多个关键词

    function highlightKeywords(text, keywords) {
        // 关键词输入形式多样性兼容
        if (Array.isArray(keywords)) {
            // 正常
        }
        else if (typeof keywords === 'string') {
            keywords = keywords.split(/\s+/); // 使用正则表达式来分割字符串,匹配一个或多个空格
        }
        else {
            throw new Error('keywords不是字符串也不是数组!');
        }

        // 遍历每个关键词
        keywords.forEach(keyword => {
            let regex = new RegExp(keyword, "gi");
            text = text.replace(regex, `<span style='color:red;'>${keyword}</span>`);
        });

        return text;
    }

    document.writeln(highlightKeywords(text, keywords)); // 模拟调用测试
</script>
<!-- 文本中将多个关键词高亮显示为红色字体 结束 -->

模拟动态筛选数据源

现代网页都是动态加载数据的,很少有纯静态网页了。在上一篇里面我们实现了静态的下拉框功能,在这里我们可以给他改成根据关键词动态筛选的。实际项目中一般使用异步加载功能(比如Ajax)调用后端api接口,加载筛选数据列表,然后绑定到选项里。

<!-- 模拟动态筛选数据源 JS脚本 开始 -->
<script>
    function filterData(keyword) {
        // 示例数组  
        const items = [
            { value: 1, text: '刘邦' },
            { value: 2, text: '刘备' },
            { value: 3, text: '刘秀' },
            { value: 4, text: '张无忌' },
            { value: 5, text: '魏无忌' },
            { value: 6, text: '何无忌' },
            { value: 7, text: '长孙无忌' }
        ];

        // 要搜索的关键词  
        keyword = keyword || 'apple';

        // 使用 filter() 方法查找匹配项  
        const matchedItems = items.filter(item => item.text.includes(keyword));
        // 输出匹配项  
        // console.log(matchedItems);
        return matchedItems;
    }

    filterData('apple'); //调用示例
</script>
<!-- 模拟动态筛选数据源 JS脚本 结束 -->

完整代码

完整代码在一个html文件里,您可以在本地新建文本文件,将完整代码复制到文件内容里面,然后重命名为: DropdownSelectBox-2.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">

    <!-- <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico"> -->
    <!-- <link href="/favicon.ico" rel="icon" type="image/x-icon"> -->

    <!-- 自动加载适应移动端的css -->
    <!-- <link href="mobile.css" rel="stylesheet" type="text/css" media="screen and (max-device-width: 1080px)"> -->

    <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';
        }

        .custom-select input[type="text"] {
            display: inline-flex;
            width: 196px;
            min-width: 1rem;
            max-width: 200px;
            border: none;
        }

        .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"></div>
        <input type="text" placeholder="关键词..." value="">
        <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 结束 -->



    <!-- 文本中将多个关键词高亮显示为红色字体 开始 -->
    <script>
        let text = "这是一段包含多个关键词的文本,例如apple、banana和orange。";
        let keywords = "apple banana orange";
        // let keywords = ["apple", "banana", "orange"]; // 关键词列表,或者空格分隔多个关键词

        function highlightKeywords(text, keywords) {
            // 关键词输入形式多样性兼容
            if (Array.isArray(keywords)) {
                // 正常
            }
            else if (typeof keywords === 'string') {
                keywords = keywords.split(/\s+/); // 使用正则表达式来分割字符串,匹配一个或多个空格
            }
            else {
                throw new Error('keywords不是字符串也不是数组!');
            }

            // 遍历每个关键词
            keywords.forEach(keyword => {
                let regex = new RegExp(keyword, "gi");
                text = text.replace(regex, `<span style='color:red;'>${keyword}</span>`);
            });

            return text;
        }

        // document.writeln(highlightKeywords(text, keywords));
    </script>
    <!-- 文本中将多个关键词高亮显示为红色字体 结束 -->

    <!-- 模拟动态筛选数据源 JS脚本 开始 -->
    <script>
        function filterData(keyword) {
            // 示例数组  
            const items = [
                { value: 1, text: '刘邦' },
                { value: 2, text: '刘备' },
                { value: 3, text: '刘秀' },
                { value: 4, text: '张无忌' },
                { value: 5, text: '魏无忌' },
                { value: 6, text: '何无忌' },
                { value: 7, text: '长孙无忌' }
            ];

            // 要搜索的关键词  
            keyword = keyword || 'apple';

            // 使用 filter() 方法查找匹配项  
            const matchedItems = items.filter(item => item.text.includes(keyword));
            // 输出匹配项  
            // console.log(matchedItems);
            return matchedItems;
        }

        // filterData('apple'); //调用示例
    </script>
    <!-- 模拟动态筛选数据源 JS脚本 结束 -->

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

            function getDom() {
                customSelect = document.querySelector('.custom-select');
                optionsList = document.querySelector('.options-list');
                options = document.querySelectorAll('.option');
            }
            getDom();

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

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

            // 使用addEventListener方法监听input事件。请注意,input事件与change事件不同。change事件在用户完成输入并且元素失去焦点时触发,或者在<select>元素中选择了一个选项时触发。而input事件则会在用户每次输入或修改值时立即触发。
            // input事件非常适用于需要即时响应用户输入的场景,比如实时搜索、输入验证等
            inputDom.addEventListener('input', function (event) {
                event.stopPropagation(); // 阻止事件冒泡到外层元素
                // event.target指向触发事件的元素,即inputElement  
                // 通过event.target.value可以获取到当前输入的值  
                // console.log('输入值已变化:', event.target.value);

                // 即时响应用户输入的场景,比如实时搜索
                var kwArray = filterData(event.target.value);
                optionsList.innerHTML = '';
                kwArray.forEach(function (item) {
                    var li = document.createElement('li');
                    li.setAttribute('class', 'option');
                    li.setAttribute('data-value', item.value);
                    // li.textContent = item.text + ' ';
                    li.innerHTML = highlightKeywords(item.text + ' ', event.target.value); //包含关键词高亮红色显示

                    bindEventToOption(li);
                    optionsList.appendChild(li);
                });
                customSelect.classList.add('active');
                getDom();

            });


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

            options.forEach(function (option) {
                bindEventToOption(option); // 选项点击事件
            });

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

            // 更新已选项的显示  
            function updateSelectedDisplay() {
                var selectedItems = [];
                getDom();

                // 搜索框里已选中项,并且不在当前选项列表里,要留存
                document.querySelectorAll('.selected-options .selectedOptions-icon-cross').forEach(function (option) {
                    var optionItem = { value: option.getAttribute('data-value'), text: option.textContent.trim() };

                    // 当前选项列表中的选项
                    var optionItemB = [];
                    options.forEach(function (optionB) {
                        optionItemB.push({ value: optionB.getAttribute('data-value'), text: optionB.textContent.trim() });
                    });
                    if (optionItemB.some(x => x == optionItem)) {
                        selectedItems.push(optionItem);
                    }
                });

                // 当前选项列表中的选中项
                options.forEach(function (option) {
                    var optionItem = { value: option.getAttribute('data-value'), text: option.textContent.trim() };
                    if (option.classList.contains('selected') && !selectedItems.some(x => x == optionItem)) {
                        selectedItems.push(optionItem);
                    }
                });

                // 清空并重新填充已选项  
                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>

效果

效果展示:

实际项目中一般使用异步加载功能(比如Ajax)调用后端api接口,加载筛选数据列表,然后绑定到选项里。
【完】

标签:function,多选,自定义,text,value,关键字,keywords,event,option
From: https://www.cnblogs.com/xiongzaiqiren/p/18582130

相关文章

  • 带有多选和突出显示关键字的自定义下拉选择框(静态)
    带有多选和突出显示关键字的自定义下拉选择框:CustomDropdownSelectBoxwithMultipleSelectionandHighlightingKeywords:不使用select元素,用div、ul、li、span元素实现带有多选和突出显示关键字的自定义下拉选择框。完整控件包含三部分:第一步用div模拟select选择框,ul+l......
  • element 的 Notification 通知,自定义内容
    https://blog.csdn.net/m0_70547044/article/details/134642743?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-134642743-blog-142925942.235%5Ev43%5Epc_blog_bottom_relevance_base4&......
  • 整型关键字的平方探测法散列 陈越
    #include<bits/stdc++.h>usingnamespacestd;map<int,int>bj;intp[30050];//埃筛法求voidgetprime(){ for(inti=1;i<=30050;i++)p[i]=1; p[0]=p[1]=0; for(inti=2;i<=30050;i++)if(p[i]==1)for(intj=2*i;j......
  • Element-Plus表格:Table自定义合并行数据的最佳实践
    “知行合一”——王阳明在开发项目中,我们时常会用到表格,许多需求可能会要求自定义特定的行或列。接下来,我们将探讨在实际开发中如何应对这一挑战。本文案例采用的技术:名称版本Vue3^3.5.12element-plus^2.8.8知识点我们先来复习下2个知识点,来自elem......
  • 通过自定义feignclient 的LoadBalancerFeignClient实现灵活的负载均衡策略
    通过自定义feignclient的LoadBalancerFeignClient或IRule能实现完全自定义的负载均衡策略,本文主要是通过实现自定义的LoadBalancerFeignClient而达到自定义的负载均衡策略示例代码实现如下:packagecn.zuowenjun.demo;importcom.netflix.loadbalancer.Server;importfeign......
  • 从 0 到 1 制作自定义镜像并用于训练(MPI+CPU/GPU)
    本章节介绍如何从0到1制作镜像,并使用该镜像在ModelArts平台上进行训练。镜像中使用的AI引擎是MPI,训练使用的资源是CPU或GPU。说明:本实践教程仅适用于新版训练作业。场景描述本示例使用Linuxx86_64架构的主机,操作系统ubuntu-18.04,通过编写Dockerfile文件制作自定义镜像。......
  • 从 0 到 1 制作自定义镜像并用于训练(Pytorch+CPU/GPU)
    本章节介绍如何从0到1制作镜像,并使用该镜像在ModelArts平台上进行训练。镜像中使用的AI引擎是PyTorch,训练使用的资源是CPU或GPU。说明:本实践教程仅适用于新版训练作业。场景描述本示例使用Linuxx86_64架构的主机,操作系统ubuntu-18.04,通过编写Dockerfile文件制作自定义镜像......
  • 通过代码实现log4net自定义配置
    大家在使用log4net的时候,常规的用法都是在配置文件里面进行设置。但是配置文件里面的配置项非常多,不利于记忆,所以说我们希望他能直接在代码中设置。于是,我写了个自定义日志配置的方法,核心的配置对象为RollingFileAppender,只需要对他进行设置就可以了。下面给大家展示下,基于......
  • .NET 项目自定义 MSBuild Task
    ......
  • vue3实现自定义导航菜单
    一、创建项目    1.打开HBuilderX图1    2.新建一个空项目        文件->新建->项目->uni-app        填写项目名称:vue3demo        选择项目存放目录:D:/HBuilderProjects        一定要注意vue的版本,当前选择的版......