WP DEVELOP

EP229. “callback 处理复杂条件:单一布尔值的限制”

首页 WordPress 开发课程 INTERACTIVITY API · EP229
约 12 分钟· #EP229#INTERACTIVITY API
🔒 登录后可标记已读

先补一个小的时序细节:答对题目时,先显示恭喜消息、等 1 秒后再真正把 solved 设为 true——避免「恭喜消息还没完全盖住答案列表」时用户就已经先看到对错图标一闪而过。这一讲真正的核心是 callback(回调)data-wp-class--{class名} 这类属性只能接受一个单一的布尔值表达式,不支持 &&/! 这类组合逻辑运算符直接写在属性里;一旦判断条件需要同时满足多个条件(比如「已解出」且「不是正确答案」才显示淡出效果),就必须把这段逻辑封装成 callbacks 对象里的一个函数,在属性里改成指向这个 callbacks.函数名


涉及文件

  • wp-content/plugins/interactivity-quiz/src/render.php (修改)
  • wp-content/plugins/interactivity-quiz/src/view.js (修改)

代码实现

src/view.js:答对后延迟 1 秒才锁定 solved,新增两个 callback

import { store, getContext } from "@wordpress/interactivity"

store("create-block", {
  actions: {
    guessAttempt: () => {
      const context = getContext()
      if (!context.solved) {
        if (context.index === context.correctAnswer) {
          context.showCongrats = true
          setTimeout(() => {
            context.solved = true
          }, 1000)
        } else {
          context.showSorry = true
          setTimeout(() => {
            context.showSorry = false
          }, 2600)
        }
      }
    },
    toggle: () => {
      const context = getContext()
      context.isOpen = !context.isOpen
    }
  },
  callbacks: {
    noclickclass: () => {
      const context = getContext()
      return context.solved && context.correct
    },
    fadedclass: () => {
      const context = getContext()
      return context.solved && !context.correct
    },
    logIsOpen: () => {
      const { isOpen } = getContext()
      // Log the value of `isOpen` each time it changes.
      console.log(`Is open: ${isOpen}`)
    }
  }
})

src/render.php<li> 标签上用 callback 驱动两个组合条件的 class

<li data-wp-class--no-click="callbacks.noclickclass" data-wp-class--fade-incorrect="callbacks.fadedclass" <?php echo wp_interactivity_data_wp_context($answer) ?> data-wp-on--click="actions.guessAttempt">
  <!-- ...内部结构不变... -->
</li>

关键改动点:

  • 时序细节:把 context.solved = true 挪进 setTimeout,延迟 1 秒执行showCongrats = true 立刻触发(提示消息开始淡入),但 solved 状态延迟 1 秒才变成 true——因为对错图标的显隐是靠 !context.solved 驱动的,如果 solved 立刻变 true,图标会在恭喜消息完全盖住答案列表之前就先短暂闪现出来,视觉上很突兀;延迟到消息动画播放到一半再改变状态,让图标出现的时机刚好被提示消息挡住,用户看不到这个「闪现」的过程
  • data-wp-class--{class名} 属性值不能是组合逻辑表达式:像 !context.correct && context.solved 这种写法直接写进 HTML 属性值会报 JS 语法错误——Interactivity API 的这类属性只接受两种形式:一个简单的 context.属性名(单一布尔值),或者一个指向 callbacks.方法名 的引用;不支持把 &&/||/! 这些运算符直接写在属性字符串里组合多个条件
  • 解法:把组合逻辑封装进 callbacks 对象callbacks.noclickclass/callbacks.fadedclass 都是无参数的箭头函数,内部先 const context = getContext() 拿到当前元素的合并后 context,再用普通 JS 逻辑运算符组合多个条件,最后 return 一个布尔值——data-wp-class/data-wp-bind 这类属性看到值是 callbacks.xxx 这种格式时,会自动调用这个函数、用它的返回值决定要不要应用
  • fadedclass(错误答案淡出效果)的条件context.solved && !context.correct——同时满足「已经解出」和「这一项不是正确答案」才淡出;noclickclass(取消正确答案的悬浮高亮)的条件:context.solved && context.correct——同时满足「已经解出」和「这一项是正确答案」才生效
  • 回调函数名字全部小写连写noclickclass/fadedclass),不是驼峰式或者带空格分隔——这是这次代码实际采用的命名风格,函数名本身可以随便取,只要 HTML 属性里引用的 callbacks.名字 和 JS 里 callbacks: {名字: () => {...}} 对应的键完全一致即可
  • 验证效果:解出题目后,正确答案失去鼠标悬浮高亮效果(看起来不再像可点击的链接),其余错误答案整体变半透明——这两个视觉效果现在都只在「真正已解出」且各自满足对应条件时才生效,不会在题目还没解出、或者条件不满足时提前触发
  • 作者留的额外练习(这一讲没有实现):目前对错图标的显隐还是用「外层 <span> 判断是否已解出 + 内层再判断是否为正确答案」这种双层嵌套 <span> 的写法,作者提示「其实也可以用 callback 把两层判断合并成一个,去掉这层嵌套结构」,留作练习题不逐步演示

Hook / Function 速查

名称类型用途
data-wp-class--{class名}="callbacks.函数名" / data-wp-bind--{属性名}="callbacks.函数名"Interactivity API 用法当条件需要组合多个布尔值(&&/`\\/!`)时,用 callback 函数封装逻辑,属性值改为引用这个函数
callbacks 对象里的函数(@wordpress/interactivityStore 结构无参数箭头函数,内部用 getContext() 取数据、return 一个布尔值,供 data-wp-class/data-wp-bind 等属性调用

常见坑

  • 直接在 data-wp-class--xxx="!context.a && context.b" 这样的属性值里写组合逻辑表达式——不支持,会在控制台报 JavaScript 错误
  • 把需要精细控制时序的状态变化都放在同一时刻执行——比如「显示提示消息」和「切换答对后的图标状态」如果都立即触发,视觉上会出现「消息还没完全遮住内容,图标却先跳出来」的穿帮效果,适当用 setTimeout 错开两者的触发时机
  • HTML 属性里引用的 callbacks.函数名 跟 JS callbacks 对象里实际定义的键名拼写不一致——不会报错,只会安静地不生效

[截图:题目解出后的最终效果——正确答案失去鼠标悬浮高亮,其余错误答案整体变半透明]


延伸 / 后续讲座会用到

下一讲要讲 state(跟 context 相对的全局共享状态)——用一个新的「已答对题目统计」Block 作为例子,展示什么时候该用 state 而不是 context


Sources

Udemy:

  • Become a WordPress Developer: Unlocking Power With Code — Section 30, EP229