EP229. “callback 处理复杂条件:单一布尔值的限制”
🔒 登录后可标记已读先补一个小的时序细节:答对题目时,先显示恭喜消息、等 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/interactivity) | Store 结构 | 无参数箭头函数,内部用 getContext() 取数据、return 一个布尔值,供 data-wp-class/data-wp-bind 等属性调用 |
常见坑
- 直接在
data-wp-class--xxx="!context.a && context.b"这样的属性值里写组合逻辑表达式——不支持,会在控制台报 JavaScript 错误 - 把需要精细控制时序的状态变化都放在同一时刻执行——比如「显示提示消息」和「切换答对后的图标状态」如果都立即触发,视觉上会出现「消息还没完全遮住内容,图标却先跳出来」的穿帮效果,适当用
setTimeout错开两者的触发时机 - HTML 属性里引用的
callbacks.函数名跟 JScallbacks对象里实际定义的键名拼写不一致——不会报错,只会安静地不生效
[截图:题目解出后的最终效果——正确答案失去鼠标悬浮高亮,其余错误答案整体变半透明]
延伸 / 后续讲座会用到
下一讲要讲 state(跟 context 相对的全局共享状态)——用一个新的「已答对题目统计」Block 作为例子,展示什么时候该用 state 而不是 context。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 30, EP229