WP DEVELOP

EP095. “编辑/取消切换与保存到 REST API”

首页 WordPress 开发课程 MY NOTES 前端功能 · EP095
约 13 分钟· #EP095#MY NOTES 前端功能
🔒 登录后可标记已读

完成两件事:① 让 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() 之类的方式调用同一个类里的其他方法,如果不 bindthis 会被 jQuery 改写指向被点击的 DOM 元素,导致 this.makeNoteReadOnlyundefined;而 deleteNote 之前没有绑定是因为它内部没有用 this 调用类的其他方法,只是巧合没出问题(这也是上一讲「常见坑」里提到的隐患)
  • updateNote() 直接复制了 deleteNote() 的 AJAX 骨架(同一个 nonce 认证方式、同一个 URL 规则),只改了三处:type"DELETE" 换成 "POST";新增 data: ourUpdatedPost 附带要更新的内容;success 回调里不再是 slideUp() 删除笔记,而是调用 this.makeNoteReadOnly(thisNote) 退出编辑模式,给用户一个「保存成功」的视觉反馈
  • ourUpdatedPost 对象的两个属性名 titlecontentWordPress 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 的指向,防止被调用方式改写

常见坑

  • editNoteupdateNote 这类内部需要用 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