Vue + Element UI 实现模糊搜索自动补全


前言

本文将以 Vue 2.x + Element UI 技术栈为基础,结合实际业务需求,详细讲解如何构建一个支持以下功能的自动补全组件:

  • 高性能模糊匹配
  • 智能时间推荐(单月/区间)
  • 动态组合模板与页面类型适配
  • 支持海量数据快速响应

一、需求分析

📌 业务场景

每个页面都有不同的提问格式要求:

  • monitor 页面:{用户} + {月度日期} + {具体问题}
    示例:广州 2024年7月 售卖情况
  • event / reason 页面:{月度日期} + {用户} + {具体问题}
    示例:2024年7月 广州 特殊事件

二、技术实现

✅ 技术选型

  • 框架:Vue 2.x
  • UI库:Element UI
  • 核心组件:el-autocomplete
  • 数据结构:动态模板 + 正则解析 + 缓存优化

2.1 基础结构 ------ 使用 el-autocomplete

vue 复制代码
<template>
  <el-autocomplete
    v-model="searchQuery"
    :fetch-suggestions="querySearchAsync"
    placeholder="请输入关键词进行搜索"
    @select="handleSelect"
  >
    <!-- 自定义下拉项显示 -->
    <template slot-scope="{ item }">
      <el-tooltip class="item" effect="dark" :content="item.value" placement="top">
        <div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 300px;">
          {{ item.value }}
        </div>
      </el-tooltip>
    </template>
  </el-autocomplete>
</template>

2.2 智能时间推荐与区间解析

🎯 需求目标

  • 输入"2024年7月" → 补全为"2024年7月"
  • 输入"7月" → 补全为"2024年7月"
  • 输入"1-7月" → 补全为"2024年1-7月"
  • "累计售电量情况"只推荐区间时间

🧠 实现思路

通过正则表达式提取用户输入中的时间信息,并根据当前年份进行补全。

js 复制代码
function parseMonthFromQuery(query, isRange = false) {
  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth() + 1;

  if (isRange) {
    // 匹配完整区间格式:2024年1-7月
    const rangeFull = query.match(/(20\d{2})年(\d{1,2})-(\d{1,2})月/);
    if (rangeFull) return [`${rangeFull[1]}年${rangeFull[2]}-${rangeFull[3]}月`];

    // 匹配简写区间格式:1-7月
    const rangeMonth = query.match(/(\d{1,2})-(\d{1,2})月/);
    if (rangeMonth) return [`${year}年${rangeMonth[1]}-${rangeMonth[2]}月`];

    // 只输入年份
    const yearMatch = query.match(/(20\d{2})/);
    if (yearMatch) return [`${yearMatch[1]}年1-${month}月`];

    // 只输入月份
    const monthMatch = query.match(/(\d{1,2})月/);
    if (monthMatch) return [`${year}年1-${parseInt(monthMatch[1], 10)}月`];

    // 默认:今年1-当前月
    return [`${year}年1-${month}月`];
  } else {
    // 单月逻辑
    const fullMatch = query.match(/(20\d{2})年(1[0-2]|0?[1-9])月/);
    if (fullMatch) return [`${fullMatch[1]}年${parseInt(fullMatch[2], 10)}月`];

    const yearMatch = query.match(/(20\d{2})/);
    if (yearMatch) return [`${yearMatch[1]}年${month}月`];

    const monthMatch = query.match(/(1[0-2]|0?[1-9])月/);
    if (monthMatch) return [`${year}年${parseInt(monthMatch[1], 10)}月`];

    return [`${year}年${month}月`];
  }
}

🧩 .match() 方法详解

  • .match(regexp) 是 JavaScript 中字符串的方法,用于执行正则表达式匹配。

  • 返回值是一个数组,包含匹配结果;如果没有匹配,则返回 null

  • 示例:

    js 复制代码
    const str = '2024年1-7月';
    const result = str.match(/(20\d{2})年(\d+)-(\d+)月/);
    // result[1] = "2024", result[2] = "1", result[3] = "7"

2.3 高性能模糊匹配与组合生成

🔍 关键优化点

  • 输入小于2个字符时不触发搜索,减少无意义计算
  • 组合生成时提前终止循环,提高性能
  • 按页面类型动态拼接模板顺序

💡 核心代码片段

js 复制代码
getSuggestions(query) {
  const results = [];
  if (!query || query.length < 2) return results;

  const questions = questionMap[this.pageType] || questionMap.monitor;
  for (const item of address) {
    for (const q of questions) {
      const isRange = q.includes('累计售卖情况');
      const smartMonths = parseMonthFromQuery(query, isRange);

      for (const month of smartMonths) {
        let name = '';
        if (this.pageType === 'monitor') {
          name = `${item.name}${month}${q}`;
        } else {
          name = `${month}${item.name}${q}`;
        }

        if (name.includes(query)) {
          results.push({ value: name, id: item.id });
          if (results.length >= 5) return results;
        }

        if (results.length >= 5) return results;
      }

      if (results.length >= 5) return results;
    }

    if (results.length >= 5) return results;
  }

  return results;
}

三、体验优化

✨ 提示优化

  • 使用 el-tooltip 显示完整内容,避免文字被截断
  • 支持高亮匹配关键词(可扩展)
  • 动态切换问题模板(通过 pageType 控制)

四、总结与扩展

🚀 本文核心价值

  • 实现了一个高性能、可扩展、智能补全的自动补全组件
  • 利用正则表达式实现了时间智能推荐与区间解析
  • 通过组合生成 + 提前终止机制优化了大数据下的响应速度
  • 支持不同页面类型的动态模板拼接
相关推荐
huxihua200613 分钟前
各种前端框架界面
前端
拾光拾趣录13 分钟前
GET/POST 的区别:从“为什么登录请求不能用 GET”说起
前端·网络协议
Carlos_sam30 分钟前
OpenLayers:ol-wind之渲染风场图全解析
前端·javascript
拾光拾趣录39 分钟前
闭包:从“变量怎么还没死”到写出真正健壮的模块
前端·javascript
拾光拾趣录1 小时前
for..in 和 Object.keys 的区别:从“遍历对象属性的坑”说起
前端·javascript
OpenTiny社区1 小时前
把 SearchBox 塞进项目,搜索转化率怒涨 400%?
前端·vue.js·github
编程猪猪侠2 小时前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞2 小时前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路2 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9492 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器