LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

前端实现连词搜索下拉效果

zhenglin
2026年2月6日 12:9 本文热度 163

前言

前端实现连词搜索下拉效果,输入框输入后根据后端返回的数据实现下拉搜索封装。

  • 使用技术 vue2+element ui


效果如下

实现思路

    • 使用watch监听输入框的值,当值改变时,传递给父组件

    • 父组件接收子组件传递的数据,请求后端接口

    • 在接口请求前和响应后做加载效果处理

    • 监听滚动区域滚动事件,使用滚动到底部加载下一页


    代码实现

    <template>

        <div class="conjunctionSearch-container">

            <!-- 搜索输入框 -->

            <div class="conjunctHead">

                <el-input clearable v-model="keywords" :placeholder="placeholder" @focus="inputFocus">

                    <el-button slot="append" icon="el-icon-search" size="mini" @click="btnClick" class="searchBtn blueText"></el-button>

                </el-input>

            </div>

            <!-- 下拉结果区 -->

            <div class="conjunctContainer" @scroll="scrollEvent" v-if="isCloseConjunction&&(scrollLoading!='state'||keywords)">

                <!-- 搜索加载 -->

                <slot name="loading">

                    <div class="loadBox searchLoad" v-if="searchLoading||scrollLoading=='state'">

                        <div class="loadIcon"></div>

                        <div class="loadText">加载中...</div>

                    </div>

                </slot>

                <!-- 用户自定义结果内容 -->

                <div class="resultBox">

                    <slot>

                        <div class="resultDefItem" v-for="item in option" :key="item[value]" @click="selectItem(item)">

                            <div class="resultDefName" :class="{'actrveDef': selectData[value]==item[value]}">{{ item[label] }}</div>

                            <div class="resultDefIcon" v-if="selectData[value]==item[value]">

                                <i class="el-icon-circle-check"></i>

                            </div>

                        </div>

                    </slot>

                </div>

                <!-- 滚动加载 -->

                <slot name="scrollLoading">

                    <div class="loadBox sollLoad" v-if="scrollLoading=='fetch'&&isScrollEnd">

                        <div class="loadIcon"></div>

                    </div>

                </slot>

                <!-- 滚动到底 -->

                <slot name="scrollEnd">

                    <div class="endText" v-if="scrollLoading=='end'&&!(isNoDataShow||noData)">没有更多了</div>

                </slot>

                <!-- 暂无数据 -->

                <slot name="noResult" v-if="isNoDataShow||(noData&&scrollLoading!='state'&&scrollLoading!='fetch')">

                    <div class="noResultBox">

                        <img src="@/assets/img/tableEmpty.png" alt="" srcset="">

                        <div class="noResultText">暂无数据</div>

                    </div>

                </slot>

            </div>

        </div>

    </template>

    <script>

    /**

     * 连词搜索功能

     * 

     * 使用方法:

     *   

     *  1.

     *  <ConjunctionSearch :option="enterpriseList" label="companyName" value="companyInfoId" @itemClick="selectItem" @search="searchChange" @scrollEnd="scrollEnd" :loading="searchLoading"  placeholder="企业名称/统一社会信用代码" />

     * 

        2. 

        <ConjunctionSearch :option="enterpriseList" label="companyName" value="companyInfoId" @itemClick="selectItem" @search="searchChange" @scrollEnd="scrollEnd" :loading="searchLoading" ref="conjunctionSearchRef" placeholder="企业名称/统一社会信用代码" >

         <div>自定义结果内容</div>

        <ConjunctionSearch/>


            // 搜索

            searchChange(val) {

                this.reqParams.keywords = val

                this.reqParams.startIndex = 1

                this.getPageList()

            }


            //滚动到底部

            scrollEnd() {

                this.reqParams.startIndex += 1

                if (this.enterpriseList.length >= this.total) {

                    this.searchLoading = 'end'

                    return

                }

                this.getPageList()

            }


            // 请求接口

             getPageList() {

                this.searchLoading = 'fetch'

                advanceSearchApi(this.reqParams).then(res => {

                    if (res.code == 0) {

                        if (this.reqParams.startIndex == 1) {

                            this.enterpriseList = res.data.dataList

                        } else {

                            this.enterpriseList = this.enterpriseList.concat(res.data.dataList)

                        }

                        this.total = res.data.total

                    }

                    this.searchLoading = this.enterpriseList.length >= this.total ? 'end' : 'success'

                })

            }

            

         属性

        @loading 加载中效果  state-开始  fetch-加载中  success-加载完成 end-结束

        @placeholder 输入框占位符

        @option 下拉选择项

        @label 下拉选项的label

        @value 下拉选项的value

        @noData 是否暂无数据


        事件

        @itemClick 选中项

        @search 搜索

        @scrollEnd 滚动到底部

     *

     *  

     */

    export default {

        props: {

            // 加载中效果  state-开始  fetch-加载中  success-加载完成 end-结束  

            loading: {

                type: String,

                default: 'state'

            },

            // 输入框占位符

            placeholder: {

                type: String,

                default: '请输入'

            },

            // 下拉选择项

            option: {

                type: Array,

                default: () => []

            },

            // 下拉选项的label

            label: {

                type: String,

                default: 'label'

            },

            // 下拉选项的value

            value: {

                type: String,

                default: 'value'

            },

            // 是否暂无数据

            noData: {

                type: Boolean,

                default: false

            }

        },

        data() {

            return {

                // 搜索关键词

                keywords: '',

                // 防抖定时器

                timer: null,

                // 搜索时的加载状态

                searchLoading: false,

                // 滚动加载中效果 state-开始  fetch-加载中  success-加载完成 end-结束  

                scrollLoading: 'state',

                // 控制下拉框显示/隐藏

                isCloseConjunction: false,

                // 是否暂无数据

                isNoDataShow: false,

                // 选中项后赋值给keywords不请求接口

                isClick: false,

                // 选中的数据

                selectData: {},

                // 是否滚动到底部

                isScrollEnd: false

            }

        },

        watch: {

            // 搜索关键词

            keywords() {

                //  选中项后赋值给keywords不请求接口

                if (this.isClick) return

                this.isCloseConjunction = true

                // 防抖

                if (this.timer) clearTimeout(this.timer)

                this.timer = setTimeout(() => {

                    this.$emit('search', this.keywords)

                }, 500)

            },

            // 搜索时的加载状态

            loading: {

                handler(val) {

                    this.scrollLoading = val

                    if (val == 'fetch') {

                        this.searchLoading = true

                    } else if (['success', 'end'].includes(val)) {

                        this.searchLoading = false

                        this.isScrollEnd = false

                    }

                }

            },

            // 默认数据

            option: {

                handler(val) {

                    this.isNoDataShow = val.length == 0

                }

            }

        },

        mounted() {

            document.addEventListener('click', this.handleClickOutside)

        },

        beforeDestroy() {

            document.removeEventListener('click', this.handleClickOutside);

        },

        methods: {

            // 点击外部关闭下拉框

            handleClickOutside(e) {

                if (!this.$el.contains(e.target)) {

                    this.isCloseConjunction = false

                }

            },

            // 滚动到底部加载

            scrollEvent(e) {

                if (['fetch', 'end'].includes(this.scrollLoading)) return

                let scrollTop = e.target.scrollTop

                let scrollHeight = e.target.scrollHeight

                let clientHeight = e.target.clientHeight

                if (scrollTop + clientHeight >= scrollHeight) {

                    this.scrollLoading = 'fetch'

                    this.isScrollEnd = true

                    this.$emit('scrollEnd')

                }

            },

            // 选中结果

            selectItem(row) {

                this.selectData = row

                this.keywords = row[this.label]

                this.isClick = true

                this.$emit('itemClick', row)

                this.close()

            },

            // 关闭下拉框

            close() {

                this.isCloseConjunction = false

            },

            // 输入框聚焦

            inputFocus() {

                this.isCloseConjunction = true

                this.isClick = false

            },

            // 按钮点击

            btnClick() {

                if (!this.keywords) {

                    return

                }

                this.$emit('search', this.keywords)

            },

        }

    }

    </script>

    <style lang="scss" scoped>

    .conjunctionSearch-container {

        width: 100%;

        position: relative;

        z-index: 2000;

        .conjunctHead {

            width: 100%;

        }

        .conjunctContainer {

            width: 100%;


            max-height: 300px;

            overflow: hidden;

            overflow-y: auto;

            border: 1px solid #ccc;

            border-radius: 5px;

            margin-top: 10px;

            background: #fff;

            box-shadow: 0 0 10px #ccc;

            position: absolute;

            z-index: 2100;

            .searchLoad {

                margin: 50px 0;

            }

            .sollLoad {

                margin: 20px 0;

            }

            .endText {

                margin: 10px 0;

                text-align: center;

                color: #ccc;

               

            }

            .noResultBox {

                margin: 30px 0;

                text-align: center;

                color: #ccc;

               

                .noResultText {

                    margin-top: 15px;

                }

            }

            .loadBox {

                text-align: center;

                display: flex;

                flex-direction: column;

                align-items: center;

                .loadIcon {

                    width: 20px;

                    height: 20px;

                    border-radius: 50%;

                    border-top: 1px solid #0052cc;

                    animation: loadAn 1s linear infinite;

                }

                .loadText {

                    margin-top: 10px;

                    color: #0052cc;

                }

            }

            .resultDefItem {

                padding: 10px 10px;

                box-sizing: border-box;

               

                cursor: pointer;

                display: flex;

                justify-content: space-between;

                .resultDefName {

                    white-space: normal;

                    text-overflow: ellipsis;

                    overflow: hidden;

                }

                .actrveDef {

                    color: #35ab6c;

                }

                .resultDefIcon {

                    color: #35ab6c;

                }

                &:hover {

                    background-color: #f2f5f9;

                }

            }

        }

    }


    @keyframes loadAn {

        0% {

            transform: rotate(0deg);

        }

        100% {

            transform: rotate(360deg);

        }

    }

    </style>


    参考文章:原文链接


    该文章在 2026/2/6 12:09:58 编辑过
    关键字查询
    相关文章
    正在查询...
    点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
    点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
    点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
    点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
    Copyright 2010-2026 ClickSun All Rights Reserved