PAYATHON 2026

Google Places Autocomplete 输入尾随空格后建议为何消失?

数据小许

结论

从给出的代码看,尾随空格不应改变实际发送的查询。事件处理器用 input.value.trim() 检查长度,并将处理后的值传给 API,所以添加或删除尾随空格时,发送的 input 通常相同。列表在失焦后重新出现,问题可能出在页面的显示状态。如果连续输入触发了多个请求,较早返回的响应也可能覆盖新结果。仅凭这段代码无法确定具体原因,可以检查浏览器开发者工具中的网络请求和控制台错误。

先检查列表是否被隐藏

输入框聚焦时,代码会移除列表的 hidden 类;点击输入框和列表之外时,则会添加这个类。输入事件处理器不会主动移除 hidden。因此,如果输入时列表已隐藏,API 请求不会让它重新显示。重新聚焦后列表再次出现,和这个行为相符。

可以在渲染结果时明确显示列表,并在查询过短或没有结果时更新列表内容,避免保留旧状态。下面的示例还会取消前一个请求,防止响应乱序时旧结果覆盖新结果:

let currentController;

async function autocomplete(query, signal) {
  const response = await fetch(
    "https://places.googleapis.com/v1/places:autocomplete",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Goog-Api-Key": API_KEY
      },
      body: JSON.stringify({ input: query }),
      signal
    }
  );

  if (!response.ok) {
    throw new Error(`Autocomplete 请求失败:${response.status}`);
  }

  const data = await response.json();
  return data.suggestions ?? [];
}

const input = document.querySelector("#address");
const results = document.querySelector("#results");

input.addEventListener("input", async () => {
  const query = input.value.trim();
  results.classList.remove("hidden");

  currentController?.abort();

  if (query.length < 3) {
    results.replaceChildren();
    const message = document.createElement("li");
    message.textContent = "Please enter at least 3 characters";
    results.appendChild(message);
    return;
  }

  const controller = new AbortController();
  currentController = controller;

  try {
    const suggestions = await autocomplete(query, controller.signal);

    // 请求期间输入内容可能已改变,忽略过期响应。
    if (query !== input.value.trim()) return;

    results.replaceChildren();

    if (suggestions.length === 0) {
      const message = document.createElement("li");
      message.textContent = "No results found";
      results.appendChild(message);
      return;
    }

    for (const suggestion of suggestions) {
      const li = document.createElement("li");
      li.textContent = suggestion.placePrediction?.text?.text ?? "";
      li.dataset.action = "select-address";
      results.appendChild(li);
    }
  } catch (error) {
    if (error.name === "AbortError") return;
    console.error(error);
  }
});

这里的 API_KEY 是从安全配置中读取的密钥。不要把真实 API key 放在公开的前端代码中。如果示例里的密钥是真实可用的,应尽快轮换,并限制它可使用的 API 和来源。

检查 HTML 结构

示例把 <input> 和 <ul> 放在 <button> 里面。button 不应包含其他交互元素,可以移除外层按钮,改用普通容器并按需要设置样式。例如:

<div class="address-container">
  <input
    type="text"
    id="address"
    placeholder="Enter address"
    class="address"
    autocomplete="off"
  >
  <ul id="results" class="address-suggestion hidden">
    <li class="three">Please enter at least 3 characters</li>
  </ul>
</div>

如何确认原因

在开发者工具的 Network 面板中,分别查看添加和删除空格时是否都发出了请求,并检查请求体中的 input、HTTP 状态码和响应内容。如果网络响应正常但列表不可见,检查 hidden 类和 CSS;如果多个请求的返回顺序与输入顺序不同,可以使用上面的取消请求和过期响应检查。也要确认 API key 和 Places API 配置有效。

备注:内容仅供参考。