WP DEVELOP

EP084. “可选:jQuery-free 版 Search.js(原生 JS + Axios)”

首页 WordPress 开发课程 前端 OVERLAY 串接自定义 API · EP084
约 16 分钟· #EP084#前端 OVERLAY 串接自定义 API
🔒 登录后可标记已读

这是一段 2020 年 6 月补录的加课,提供一份不依赖 jQuery、可以直接整份替换掉现有 Search.js 的版本。用意是让打包出来的 JS 体积更小、加载更快,同时练习一下业界更常见的原生 DOM API + Axios 写法。作者没有逐行讲解,只是过了一遍主要差异点;文件可以直接下载替换使用,功能跟原本的 jQuery 版完全一致。


涉及文件

  • wp-content/themes/fictional-university-theme/src/modules/Search.js (整份替换)

代码实现

完整的 jQuery-free 版本(课程资源直接提供下载,整份复制替换掉原文件):

// wp-content/themes/fictional-university-theme/src/modules/Search.js
import axios from "axios"

class Search {
  constructor() {
    this.addSearchHTML()
    this.resultsDiv = document.querySelector("#search-overlay__results")
    this.openButton = document.querySelectorAll(".js-search-trigger")
    this.closeButton = document.querySelector(".search-overlay__close")
    this.searchOverlay = document.querySelector(".search-overlay")
    this.searchField = document.querySelector("#search-term")
    this.isOverlayOpen = false
    this.isSpinnerVisible = false
    this.previousValue
    this.typingTimer
    this.events()
  }

  events() {
    this.openButton.forEach(el => {
      el.addEventListener("click", e => {
        e.preventDefault()
        this.openOverlay()
      })
    })

    this.closeButton.addEventListener("click", () => this.closeOverlay())
    document.addEventListener("keydown", e => this.keyPressDispatcher(e))
    this.searchField.addEventListener("keyup", () => this.typingLogic())
  }

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

      if (this.searchField.value) {
        if (!this.isSpinnerVisible) {
          this.resultsDiv.innerHTML = '<div class="spinner-loader"></div>'
          this.isSpinnerVisible = true
        }
        this.typingTimer = setTimeout(this.getResults.bind(this), 750)
      } else {
        this.resultsDiv.innerHTML = ""
        this.isSpinnerVisible = false
      }
    }

    this.previousValue = this.searchField.value
  }

  async getResults() {
    try {
      const response = await axios.get(universityData.root_url + "/wp-json/university/v1/search?term=" + this.searchField.value)
      const results = response.data
      this.resultsDiv.innerHTML = `
        <!-- 三栏布局 HTML 结构跟 EP078/079 完全一致,只是外层从 $.getJSON 回调改成 async/await -->
      `
      this.isSpinnerVisible = false
    } catch (e) {
      console.log(e)
    }
  }

  keyPressDispatcher(e) {
    if (e.keyCode == 83 && !this.isOverlayOpen && document.activeElement.tagName != "INPUT" && document.activeElement.tagName != "TEXTAREA") {
      this.openOverlay()
    }

    if (e.keyCode == 27 && this.isOverlayOpen) {
      this.closeOverlay()
    }
  }

  openOverlay() {
    this.searchOverlay.classList.add("search-overlay--active")
    document.body.classList.add("body-no-scroll")
    this.searchField.value = ""
    setTimeout(() => this.searchField.focus(), 301)
    this.isOverlayOpen = true
    return false
  }

  closeOverlay() {
    this.searchOverlay.classList.remove("search-overlay--active")
    document.body.classList.remove("body-no-scroll")
    this.isOverlayOpen = false
  }

  addSearchHTML() {
    document.body.insertAdjacentHTML(
      "beforeend",
      `
      <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>
    `
    )
  }
}

export default Search

jQuery 版 → 原生版对照表

jQuery 写法原生 JS 写法说明
$(selector)document.querySelector(selector)选中第一个匹配元素
$(selector)(多个元素)document.querySelectorAll(selector)返回 NodeList,需要手动 forEach 遍历后逐个 addEventListener(jQuery 会自动对集合里每个元素生效,原生 API 不会)
.on("click", fn).addEventListener("click", fn)事件绑定
$.getJSON(url, callback)axios.get(url) + async/await发请求;改用 try/catch 处理错误,而不是回调
.html(str).innerHTML = str注意原生是「属性赋值」不是方法调用
.addClass() / .removeClass().classList.add() / .classList.remove()操作 CSS class
$("body").append(html)document.body.insertAdjacentHTML("beforeend", html)插入 HTML 片段

Hook / Function 速查

名称类型用途
axios.get(url)第三方库(Axios)发送 HTTP GET 请求,返回 Promise,是业界通用的 HTTP 请求库,跟 WordPress/jQuery 无关
document.querySelectorAll()浏览器原生 API选中所有匹配的元素,返回 NodeList
element.classList浏览器原生 API操作元素的 CSS class(add/remove/toggle)
element.insertAdjacentHTML(position, html)浏览器原生 API在指定位置插入 HTML 字符串

常见坑

  • document.querySelectorAll() 返回的是集合(NodeList),不能像 jQuery 对象那样直接 .addEventListener(),必须先 forEach 手动遍历,逐个绑定事件——这是原生写法比 jQuery 多出来的一步
  • async/await 发请求时要记得包 try/catch,不然请求失败会导致整个函数直接报错中断,而不是像 jQuery 那样安静地失败

Sources

Udemy:

  • Become a WordPress Developer: Unlocking Power With Code — Section 16, EP084