EP095. “编辑/取消切换与保存到 REST API”
🔒 登录后可标记已读完成两件事:① 让 Edit 按钮变成一个「编辑/取消」双态切换按钮——点一次进入编辑模式(按钮变 Cancel),再点一次退出编辑模式(变回 Edit),用 data-state 属性记录当前笔记处于哪种状态;② 实现 Save 按钮,点击后把标题和正文打包发一个 POST 请求给 REST API,成功后自动退出编辑模式。至此 CRUD 里的 U(Update)也完成了。
涉及文件
wp-content/themes/fictional-university-theme/src/modules/MyNotes.js(修改)
代码实现
src/modules/MyNotes.js(完整改动后的关键部分):
// wp-content/themes/fictional-university-theme/src/modules/MyNotes.js
events() {
$(".delete-note").on("click", this.deleteNote)
$(".edit-note").on("click", this.editNote.bind(this)) // 修改:加 .bind(this)
$(".update-note").on("click", this.updateNote.bind(this)) // 新增
}
editNote(e) {
var thisNote = $(e.target).parents("li")
if (thisNote.data("state") == "editable") {
this.makeNoteReadOnly(thisNote)
} else {
this.makeNoteEditable(thisNote)
}
}
// 新增:拆成两个「相反」的方法,各自负责一种状态
makeNoteEditable(thisNote) {
thisNote.find(".edit-note").html('<i class="fa fa-times" aria-hidden="true"></i> Cancel')
thisNote.find(".note-title-field, .note-body-field").removeAttr("readonly").addClass("note-active-field")
thisNote.find(".update-note").addClass("update-note--visible")
thisNote.data("state", "editable")
}
makeNoteReadOnly(thisNote) {
thisNote.find(".edit-note").html('<i class="fa fa-pencil" aria-hidden="true"></i> Edit')
thisNote.find(".note-title-field, .note-body-field").attr("readonly", "readonly").removeClass("note-active-field")
thisNote.find(".update-note").removeClass("update-note--visible")
thisNote.data("state", "cancel")
}
// 新增:保存到 REST API
updateNote(e) {
var thisNote = $(e.target).parents("li")
var ourUpdatedPost = {
"title": thisNote.find(".note-title-field").val(),
"content": thisNote.find(".note-body-field").val()
}
$.ajax({
beforeSend: xhr => {
xhr.setRequestHeader("X-WP-Nonce", universityData.nonce)
},
url: universityData.root_url + "/wp-json/wp/v2/note/" + thisNote.data("id"),
type: "POST",
data: ourUpdatedPost,
success: response => {
this.makeNoteReadOnly(thisNote)
console.log("Congrats")
console.log(response)
},
error: response => {
console.log("Sorry")
console.log(response)
}
})
}
关键改动点:
editNote(e)本身只做「判断状态、转发调用」这一件事:检查thisNote.data("state")是不是"editable",是就调用makeNoteReadOnly(),不是就调用makeNoteEditable()——两个具体方法各自负责一种状态下要做的四件事(按钮文案+图标、输入框只读状态、高亮样式、Save 按钮显隐),刻意拆成「一对相反的方法」而不是堆在一起写 if/else,逻辑更清楚makeNoteEditable()/makeNoteReadOnly()最后都会更新thisNote.data("state", ...),这是下次点击时editNote()能正确判断该往哪个方向切换的关键——第一次进页面没有这个属性,天然会走「变成可编辑」分支.on("click", this.editNote.bind(this))和this.updateNote.bind(this)都显式加了.bind(this):因为这两个方法内部都要用this.makeNoteReadOnly()之类的方式调用同一个类里的其他方法,如果不bind,this会被 jQuery 改写指向被点击的 DOM 元素,导致this.makeNoteReadOnly是undefined;而deleteNote之前没有绑定是因为它内部没有用this调用类的其他方法,只是巧合没出问题(这也是上一讲「常见坑」里提到的隐患)updateNote()直接复制了deleteNote()的 AJAX 骨架(同一个 nonce 认证方式、同一个 URL 规则),只改了三处:type从"DELETE"换成"POST";新增data: ourUpdatedPost附带要更新的内容;success回调里不再是slideUp()删除笔记,而是调用this.makeNoteReadOnly(thisNote)退出编辑模式,给用户一个「保存成功」的视觉反馈ourUpdatedPost对象的两个属性名title和content是 WordPress REST API 固定认的字段名,不能自己随便取名——这跟前面自己写的自定义端点(search-route.php)不同,这里用的是 WordPress 内建的文章更新端点,字段名必须匹配它的约定
[截图:前台点击 Save 按钮保存笔记后,输入框恢复只读状态、Edit 按钮文案变回 "Edit" 的样子]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
.data(key, value) | jQuery 方法 | 传两个参数时是「写入」data-* 属性值(内存中,非直接改 HTML),只传一个参数时是「读取」 |
.attr(name, value) | jQuery 方法 | 设置元素的 HTML 属性 |
.val() | jQuery 方法 | 读取表单元素(input/textarea)当前的值 |
.bind(this) | JS 内建方法 | 固定函数内部 this 的指向,防止被调用方式改写 |
常见坑
editNote、updateNote这类内部需要用this.xxx()调用其他方法的回调,绑定事件时忘记加.bind(this)——不加的话this会指向被点击的 DOM 元素而不是MyNotes实例,调用this.makeNoteReadOnly会直接报错- 发给 WordPress 内建 REST API 端点的数据字段名写错——必须用
title/content这种 WordPress 约定的字段名,不能像自定义端点那样随便取名 - 忘记给
ourUpdatedPost传值就直接发请求——两个字段的值都要现从thisNote.find(...)里.val()读取当前输入框/文本域的最新内容,不能用页面刚加载时的旧值
延伸 / 后续讲座会用到
CRUD 四个操作还差最后一个「创建(Create)」,下一讲开始学怎么在前端新建一条笔记。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 19, EP095