EP084. “可选:jQuery-free 版 Search.js(原生 JS + Axios)”
🔒 登录后可标记已读这是一段 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