EP111. “可选:jQuery-free 版 Like.js(原生 JS + Axios)”
🔒 登录后可标记已读📌 并入 EP110 的提醒(实际代码修复):解决 EP108/EP109 提到的 PHP 警告——未点赞时 $existQuery->posts[0]->ID 访问的是不存在的数组项。single-professor.php 里 .like-box 的 data-like 属性要改成:
data-like="<?php if (isset($existQuery->posts[0]->ID)) echo $existQuery->posts[0]->ID; ?>"
用 isset() 先判断这个数组项存不存在,存在才输出,不存在就干脆不输出(属性值留空),避免 PHP 对着不存在的数组下标发警告。
跟 Search.js(EP084)、MyNotes.js(EP102)一样是同一模式的补录加课:提供一份不依赖 jQuery、用原生 JS + Axios 重写的 Like.js,可以直接整份替换。功能表现完全一致,作者提到这里没有引入任何新概念,纯粹是练习巩固前两次已经讲过的「原生 DOM API 替代 jQuery」的写法。
涉及文件
wp-content/themes/fictional-university-theme/single-professor.php(修改,isset()修复)wp-content/themes/fictional-university-theme/src/modules/Like.js(整份替换)
代码实现
完整的 jQuery-free 版本(课程资源直接提供下载,整份复制替换掉原文件):
// wp-content/themes/fictional-university-theme/src/modules/Like.js
import axios from "axios"
class Like {
constructor() {
if (document.querySelector(".like-box")) {
axios.defaults.headers.common["X-WP-Nonce"] = universityData.nonce
this.events()
}
}
events() {
document.querySelector(".like-box").addEventListener("click", e => this.ourClickDispatcher(e))
}
ourClickDispatcher(e) {
let currentLikeBox = e.target
while (!currentLikeBox.classList.contains("like-box")) {
currentLikeBox = currentLikeBox.parentElement
}
if (currentLikeBox.getAttribute("data-exists") == "yes") {
this.deleteLike(currentLikeBox)
} else {
this.createLike(currentLikeBox)
}
}
async createLike(currentLikeBox) {
try {
const response = await axios.post(universityData.root_url + "/wp-json/university/v1/manageLike", { "professorId": currentLikeBox.getAttribute("data-professor") })
if (response.data != "Only logged in users can create a like.") {
currentLikeBox.setAttribute("data-exists", "yes")
var likeCount = parseInt(currentLikeBox.querySelector(".like-count").innerHTML, 10)
likeCount++
currentLikeBox.querySelector(".like-count").innerHTML = likeCount
currentLikeBox.setAttribute("data-like", response.data)
}
console.log(response.data)
} catch (e) {
console.log("Sorry")
}
}
async deleteLike(currentLikeBox) {
try {
const response = await axios({
url: universityData.root_url + "/wp-json/university/v1/manageLike",
method: 'delete',
data: { "like": currentLikeBox.getAttribute("data-like") },
})
currentLikeBox.setAttribute("data-exists", "no")
var likeCount = parseInt(currentLikeBox.querySelector(".like-count").innerHTML, 10)
likeCount--
currentLikeBox.querySelector(".like-count").innerHTML = likeCount
currentLikeBox.setAttribute("data-like", "")
console.log(response.data)
} catch (e) {
console.log(e)
}
}
}
export default Like
关键改动点:
- constructor 里先判断
document.querySelector(".like-box")是否存在,只有教授详情页才会跑这段逻辑,其他页面直接跳过——这个「先判断相关元素存不存在」的写法在 EP102 的 MyNotes.js 里也用过,是这系列 jQuery-free 重写共同的习惯 - nonce 同样是在 constructor 里用
axios.defaults.headers.common["X-WP-Nonce"]全局设置一次,createLike()/deleteLike()内部不用再单独处理 ourClickDispatcher用while (!currentLikeBox.classList.contains("like-box")) { currentLikeBox = currentLikeBox.parentElement }手写「向上找最近的.like-box祖先」逻辑,等价于 jQuery 版的.closest(".like-box")createLike()里多了一层判断:if (response.data != "Only logged in users can create a like.")才更新界面——因为用 Axios 时,只要 HTTP 状态码不是 2xx 才会走catch,而这个端点在「未登录」时是用die()提前终止并返回一段文字(状态码可能依然是 200),所以要显式检查返回内容是不是那句拒绝文案,避免把「其实被拒绝了」误判成「点赞成功」deleteLike()用了axios({ url, method: 'delete', data })这种更完整的对象写法,而不是axios.delete(url, data)的简写——这是因为 Axios 的.delete()简写方法在传递请求体(data)时的参数位置和普通的 GET/POST 简写不太一样,用完整对象写法可以更明确地把data传过去,不容易出错
Hook / Function 速查
本讲没有出现新的 WordPress hook 或 function,是对已学过的原生 JS 写法(querySelector、classList、setAttribute、parentElement、axios + async/await)的巩固练习,具体可参考 EP084、EP102 的速查表。
常见坑
- 用 Axios 时以为服务端
die()提前终止请求一定会让请求「失败」(触发catch)——die()只是提前结束 PHP 输出,HTTP 状态码不一定是错误码,前端必须显式检查返回内容而不能只依赖 try/catch 的成功与否来判断业务是否真的成功 isset()判断只加在读取的地方、却忘了这本来是为了消除 PHP 警告,不是为了改变功能逻辑——修复后即使数组项不存在,属性值就是空字符串,不影响后续 JS 里data-exists/data-like的判断逻辑
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 20, EP111(含 EP110 提醒并入)