浏览器级“实时搜索联想”前端实现总结

浏览器级“实时搜索联想”前端实现总结

浏览器级“实时搜索联想”前端实现总结

1. 目标

  • 搜索框的联想词不是本地写死数组,而是像 Chrome 地址栏一样,实时调用搜索引擎官方建议接口

  • 点击/回车后跳转到真正的搜索结果页(百度/Google/Bing 等)。


2. 核心思路

  1. 监听输入框 input 事件。

  2. 动态拼接搜索引擎的建议 API(JSONP 或 CORS-JSON)。

  3. 返回结果 → 渲染下拉列表。

  4. 用户确认 → window.open(_blank) 在新标签打开搜索结果。


3. 主流建议接口速查

| 引擎 | 接口(GET) | 返回格式 | 备注 |

| ---------- | ------------------------------------------------------------ | --------- | ------------------ |

| 百度 | https://suggestion.baidu.com/su?wd=关键词&cb=xxx | JSONP | 无限制,最稳定 |

| Google | https://www.google.com/complete/search?client=firefox&q=关键词 | JSON | 部分地区需科学上网 |

| Bing | https://www.bing.com/AS/Suggestions?pt=page.home&mkt=zh-cn&qry=关键词 | HTML 片段 | 需解析 DOM |


4. 最小可运行示例(百度版)

把下面代码保存为 index.html 即可直接体验。


<!doctype html>

<html lang="zh-CN">

<head>

  <meta charset="UTF-8"/>

  <title>实时搜索联想 Demo</title>

  <style>

    * { box-sizing: border-box; }

    body { font: 16px/1.5 -apple-system, Roboto; background: #f5f5f5; margin: 0; }

    .search-box { position: relative; width: 520px; margin: 80px auto; }

    #searchInput { width: 100%; padding: 10px 15px; font-size: 16px; border: 1px solid #bbb; border-radius: 4px; outline: none; }

    #searchBtn { position: absolute; right: -80px; top: 0; width: 80px; height: 100%; border: 1px solid #bbb; border-left: 0; border-radius: 0 4px 4px 0; background: #0084ff; color: #fff; cursor: pointer; }

    #searchBtn:hover { background: #006acc; }

    .suggest { position: absolute; left: 0; right: 0; top: 100%; margin: 0; padding: 0; list-style: none; background: #fff; border: 1px solid #bbb; border-top: 0; max-height: 300px; overflow-y: auto; z-index: 999; }

    .suggest li { padding: 8px 15px; cursor: pointer; }

    .suggest li:hover, .suggest li.active { background: #f0f0f0; }

  </style>

</head>

<body>

  <div class="search-box">

    <input id="searchInput" type="text" autocomplete="off" placeholder="输入关键词,实时获取百度联想" />

    <button id="searchBtn">搜索</button>

    <ul id="suggestList" class="suggest"></ul>

  </div>



  <script>

    const input = document.getElementById('searchInput');

    const btn   = document.getElementById('searchBtn');

    const list  = document.getElementById('suggestList');

    let idx = -1;

    const cache = {};



    input.addEventListener('input', onInput);

    input.addEventListener('keydown', onKey);

    btn.addEventListener('click', () => doSearch(input.value.trim()));



    function onInput() {

      const kw = input.value.trim();

      if (!kw) return hideList();

      if (cache[kw]) return renderList(cache[kw]);

      const script = document.createElement('script');

      script.src = `https://suggestion.baidu.com/su?wd=${encodeURIComponent(kw)}&cb=handleBaiduSuggest`;

      document.body.appendChild(script);

      script.onload = () => script.remove();

    }



    window.handleBaiduSuggest = function (res) {

      const arr = res.s || [];

      cache[res.q] = arr;

      renderList(arr);

    };



    function renderList(arr) {

      if (!arr.length) return hideList();

      list.innerHTML = '';

      arr.forEach((text, i) => {

        const li = document.createElement('li');

        li.textContent = text;

        li.addEventListener('click', () => {

          input.value = text;

          doSearch(text);

        });

        list.appendChild(li);

      });

      list.style.display = 'block';

      idx = -1;

    }



    function hideList() { list.style.display = 'none'; }



    function onKey(e) {

      const items = list.querySelectorAll('li');

      if (!items.length) return;

      if (e.key === 'ArrowDown') { idx = Math.min(idx + 1, items.length - 1); updateActive(items); }

      else if (e.key === 'ArrowUp') { idx = Math.max(idx - 1, -1); updateActive(items); }

      else if (e.key === 'Enter') {

        if (idx >= 0) input.value = items[idx].textContent;

        doSearch(input.value.trim());

      } else if (e.key === 'Escape') { hideList(); }

    }



    function updateActive(items) { items.forEach((li, i) => li.classList.toggle('active', i === idx)); }



    function doSearch(kw) {

      if (!kw) return;

      hideList();

      window.open('https://www.baidu.com/s?wd=' + encodeURIComponent(kw), '_blank');

    }

  </script>

</body>

</html>

---

*本文由[萧兮的博客](https://www.20010515.xyz)原创发布,欢迎转载,转载务必保留原文链接。*

**萧兮的博客**:[https://www.20010515.xyz](https://www.20010515.xyz)  ·  原文:[https://www.20010515.xyz/posts/84a12786-bb99-4e82-a141-e0f05a2f7979](https://www.20010515.xyz/posts/84a12786-bb99-4e82-a141-e0f05a2f7979)