WP DEVELOP

EP070. “搜索 Overlay 的几个体验细节优化”

首页 WordPress 开发课程 LIVE SEARCH(续) · EP070
约 16 分钟· #EP070#LIVE SEARCH(续)
🔒 登录后可标记已读

篇幅比较短,做四件跟 REST API 本身没关系的体验优化:把原本写死在 footer.php 里的 overlay HTML 搬到 Search.js 用 JS 动态插入(这样禁用 JS 的访客不会白白多下载这段永远打不开的 HTML);把打字停顿等待时间从 2000 毫秒缩短到 750 毫秒;overlay 打开后自动把光标定位到搜索框(但要等 CSS 淡入动画播完,否则很多浏览器 focus 不会生效);以及每次关闭 overlay 再重新打开时自动清空上次搜索的内容。

涉及文件

  • wp-content/themes/fictional-university-theme/footer.php (修改,删掉写死的 search-overlay HTML 区块)
  • wp-content/themes/fictional-university-theme/src/modules/Search.js (修改,新增 addSearchHTML() 方法,调整 typingTimer 的等待毫秒数,openOverlay() 新增清空输入框 + 延迟 focus 的逻辑)

代码实现

footer.php 删掉这一整块(原本在 </footer><?php wp_footer(); ?> 之间):

<!-- footer.php:删掉,搬去 Search.js 里用 JS 动态生成 -->
<div class="search-overlay">
  <div class="search-overlay__top">
    <div class="container">
      <i class="fa fa-search search-overlay__icon" aria-hidden="true"></i>
      <input type="text" class="search-term" placeholder="What are you looking for?" id="search-term">
      <i class="fa fa-window-close search-overlay__close" aria-hidden="true"></i>
    </div>
  </div>

  <div class="container">
    <div id="search-overlay__results"></div>
  </div>
</div>

Search.js 改动:

// wp-content/themes/fictional-university-theme/src/modules/Search.js

class Search {
  constructor() {
    // 新增:必须放在最前面,因为下面几行要选取的元素(#search-term 等)
    // 这时候才刚被 addSearchHTML() 插入到 DOM 里
    this.addSearchHTML()
    this.resultsDiv = $("#search-overlay__results")
    this.openButton = $(".js-search-trigger")
    this.closeButton = $(".search-overlay__close")
    this.searchOverlay = $(".search-overlay")
    this.searchField = $("#search-term")
    this.events()
    this.isOverlayOpen = false
    this.isSpinnerVisible = false
    this.previousValue
    this.typingTimer
  }

  // ...events() 不变...

  typingLogic() {
    if (this.searchField.val() != this.previousValue) {
      clearTimeout(this.typingTimer)

      if (this.searchField.val()) {
        if (!this.isSpinnerVisible) {
          this.resultsDiv.html('<div class="spinner-loader"></div>')
          this.isSpinnerVisible = true
        }
        // 修改:等待时间从 2000 缩短到 750 毫秒
        this.typingTimer = setTimeout(this.getResults.bind(this), 750)
      } else {
        this.resultsDiv.html("")
        this.isSpinnerVisible = false
      }
    }

    this.previousValue = this.searchField.val()
  }

  // ...getResults() 不变(还是 EP069 那版)...

  openOverlay() {
    this.searchOverlay.addClass("search-overlay--active")
    $("body").addClass("body-no-scroll")
    // 新增:每次打开都先清空上一次搜索的内容
    this.searchField.val("")
    // 新增:等 301 毫秒(CSS 淡入过渡刚好跑完)再 focus,
    // 立刻 focus 在很多浏览器里因为元素还没被视为"可见"而不会生效
    setTimeout(() => this.searchField.focus(), 301)
    console.log("our open method just ran!")
    this.isOverlayOpen = true
  }

  closeOverlay() {
    this.searchOverlay.removeClass("search-overlay--active")
    $("body").removeClass("body-no-scroll")
    console.log("our close method just ran!")
    this.isOverlayOpen = false
  }

  // 新增:把原本写死在 footer.php 里的 overlay HTML 搬过来,用 jQuery append 到 body 最底部
  addSearchHTML() {
    $("body").append(`
      <div class="search-overlay">
        <div class="search-overlay__top">
          <div class="container">
            <i class="fa fa-search search-overlay__icon" aria-hidden="true"></i>
            <input type="text" class="search-term" placeholder="What are you looking for?" id="search-term">
            <i class="fa fa-window-close search-overlay__close" aria-hidden="true"></i>
          </div>
        </div>
        
        <div class="container">
          <div id="search-overlay__results"></div>
        </div>

      </div>
    `)
  }
}

要点:

  • addSearchHTML() 必须在构造函数最开头就调用,顺序反了的话,this.resultsDiv = $("#search-overlay__results") 这些选择器这时候在 DOM 里根本还找不到对应元素(因为 HTML 还没插进去),会拿到空的 jQuery 对象。
  • $("body").append(\...\) 用的也是模板字符串反引号,方便把整段 HTML 保持多行缩进书写。
  • setTimeout(() => this.searchField.focus(), 301):这里的箭头函数同样是为了让 this 继续指向 Search 对象,而不是被 setTimeout 劫持。
  • 清空输入框用的是 this.searchField.val(""),跟读取输入框内容的 this.searchField.val()(不传参数)是同一个 jQuery 方法,传空字符串就是"设置"用法。

Hook / Function 速查

名称类型用途
$(selector).append(html)jQuery 方法把一段 HTML 插入到被选中元素内容的最后面
setTimeout(fn, ms)JS 内建 function等待指定毫秒数后执行一次某个函数
$(selector).val() / $(selector).val("")jQuery 方法不传参数时读取表单元素当前值;传字符串参数时是设置该值
$(selector).focus()jQuery 方法让某个表单元素获得输入焦点(光标定位过去)

常见坑

  • overlay 的显示/隐藏是靠 CSS class 切换配合过渡动画(大约 300 毫秒淡入淡出),如果 openOverlay() 里的类名加上去之后立刻同步调用 .focus(),很多浏览器(包括讲师演示用的这版 Chrome)会因为元素此时还没被认为是"可见"而 focus 失败,必须用 setTimeout 等过渡跑完(比如 301 毫秒)再 focus。
  • addSearchHTML() 如果没有放在构造函数最前面执行,后面几行选取 #search-overlay__results#search-term 等元素的代码会因为 DOM 里还没有这些元素而选空。

延伸 / 后续讲座会用到

下一讲 EP071 开始学习让搜索同时覆盖多种文章类型(posts + pages),并在 EP072 用 $.when().then() 重构成并行请求。

Sources

Udemy:

  • Become a WordPress Developer: Unlocking Power With Code — Section 14, EP070