EN
Shopify 知识库 · 指南

Dawn 预测搜索:建议请求、键盘行为与结果页

基于 Dawn v15.3.0 固定源码,追踪页头搜索弹层、predictive-search 元素、/search/suggest 分区请求、combobox 标记、键盘与状态播报,并对照站内搜索契约列出差距。
历史资料
请结合文中的适用版本和来源阅读。

本文基于 Dawn v15.3.0,源码固定到 ecb06c3(核验于 2026-09-29)。结论限于此提交,不表示其他版本行为相同;本篇为静态源码分析,未完成店铺运行验证。Dawn 上游已发布 v16.0.0(2026-08-10,GitHub Releases 核对),本库 Dawn 正文统一以 v15.3.0 为基线,升级前需重新核对。

对应哪些通用模式

主要对应站内搜索模块:搜索框、建议、结果页与无结果。建议面板是绝对定位的 div,由 <predictive-search> 的 open 属性与 CSS 显示;在固定提交的全仓库搜索中,popovertarget、popover=、showPopover、hidePopover 均未命中,所以它不是Popover所指的原生 Popover API 实现,只能在“紧贴输入框的非模态浮层”上类比。搜索入口本身在带 role="dialog" 的弹层里,属于模态形态。

入口与文件

文件职责何时输出
snippets/header-search.liquiddetails-modal 内的搜索弹层与输入框;开关决定包裹 <predictive-search> 还是 <search-form>页头
sections/header.liquid渲染上述片段:top-center 布局或未选菜单时多渲染一份(Search-In-Modal-1),另一份 Search-In-Modal,CSS 按断点显示其一页头
sections/predictive-search.liquid无 schema,只作建议请求的返回体:role="listbox" 结果、“Search for”选项、计数文本仅建议响应
assets/predictive-search.js、search-form.js请求、渲染、键盘、状态;后者提供 300ms 防抖与清除按钮开关为真才加载前者
sections/main-search.liquid、main-search.js结果页搜索框、计数、paginate 每页 24、筛选与排序(复用 facets 片段)templates/search.json

layout/theme.liquid 在 head 加载 search-form.js,文末按 predictive_search_enabled 加载 predictive-search.js,并写入 window.routes.predictive_search_url。

数据从哪来

  • 请求:fetch 请求 routes.predictive_search_url(Liquid 路由值,通用页记该端点为 /search/suggest)加查询串 ?q=<编码词>&section_id=predictive-search。只传 q 与 section_id,不传 resources[type]、resources[limit]、resources[options][unavailable_products],类型、数量与缺货处理走平台默认与 Search & Discovery 设置(默认值见站内搜索模块「映射到 Shopify」)。
  • Liquid 对象:predictive_search.performed、.terms、.resources.queries / collections / pages / articles / products;查询建议用 query.styled_text,价格经 price 片段。
  • 商家设置(config/settings_schema.json「Search behavior」):predictive_search_enabled(默认 true)、predictive_search_show_vendor、predictive_search_show_price(默认 false)。

交互怎样运行

  1. 输入经 300ms 防抖调用 onChange;不再相关的旧结果被移除,空词则关闭并清空。
  2. getSearchResults 先查内存缓存(键为小写词,仅替换第一个空格);未命中则请求,取响应里 #shopify-section-predictive-search 的 innerHTML,并同步写入页面全部实例的缓存。
  3. 渲染后写 open、aria-expanded="true",按视口与页头底部算面板 max-height;请求期间设 loading 属性,CSS 据此显示旋转图标。
  4. 键盘:keyup 的上下键在可见 li 与“Search for”按钮间循环,写 aria-selected 与 aria-activedescendant;Enter 点击选中项;keydown 阻止上下键移动光标。焦点始终在输入框。
  5. 焦点离开后异步关闭;重置按钮清空输入、中止请求并关闭。
  6. 无 JS 时它是指向搜索页的 GET 表单(隐藏字段 options[prefix]=last),建议只是增强。

与通用契约的一致与差距

契约(站内搜索)Dawn v15.3.0判断
combobox 结构与焦点输入框有 role="combobox"、aria-expanded、aria-controls、aria-autocomplete="list"、aria-haspopup="listbox";选项 role="option",链接 tabindex="-1",焦点留在输入框一致;aria-owns 与 aria-controls 指向同一 id,实际朗读未核验
listbox 子结构分组用 ul role="group",但 h2 与 div 容器也在 listbox 内是否兼容 APG 预期,未核验
Escapepredictive-search.js 未处理;页头由外层 details-modal 在 keyup 关闭整个弹层并把焦点还给触发按钮,结果页搜索框无对应处理差距:没有“先关建议、再清输入”
不自动选中、Enter打开时无选中项;有选中链接则阻止提交并点击,否则原生提交原词一致;Home、End、Alt+方向键未处理(契约中为可选)
结果数量通知视觉隐藏的 role="status" 节点先写“加载中”,再写隐藏节点里的计数文案,1 秒后设 aria-hidden="true";结果页另有 <p role="status">有实现;aria-hidden 切换的播报效果未核验
建议为空面板仍显示“Search for”选项,状态文本读无结果文案与“收起面板”不同
取消过期请求AbortController 只在重置按钮时中止;连续输入不取消旧请求,也不校验响应是否过期差距:乱序响应可能覆盖新结果(静态推断,未复现)
请求失败非 2xx 或异常时 close() 并抛错,无可见提示与重试,429 同样处理差距:失败表现为面板消失
无结果页<p role="status"> 回显词并提示检查拼写;已读的 main-search.liquid 中未见热门分类或客服入口部分一致
拼写容错回显全仓库搜索未找到(搜索词:spell、did you mean、showing results for、corrected;仅命中 spellcheck="false" 与无结果文案)主题未内置;平台是否提供字段未核验
同页多个搜索页头至多两份,结果页再一份;结果标记里的 predictive-search-results 等 id 在多实例同时渲染时会重复风险,是否同时渲染未核验

定制入口与风险

商家侧只有上述三个主题设置。开发侧耦合点:predictive-search-results、predictive-search-option-* 与 #shopify-section-predictive-search 被 JS 硬编码依赖;switchOption 依赖 li 与 button.predictive-search__item;页面、文章列表在桌面与移动各输出一份并靠 CSS 隐藏;sticky-header 在建议打开时忽略滚动。改标记或加入 resources[...] 参数时需同步检查。

建议的验证范围

本篇均未执行:页头与结果页分别输入英文、中文词,核对 /search/suggest 的请求与响应;限速下连续输入,确认乱序;断网与模拟 429,确认面板与状态文本;只用键盘完成输入、选择、提交与 Escape;用读屏软件核对计数播报;top-center 布局下检查重复 id。

源码基线