EP137. “Attributes 机制:让 Block 真正可交互”
🔒 登录后可标记已读学习 Gutenberg Block 最核心的数据机制——attributes(属性):在 registerBlockType() 的配置对象里声明这个 Block 需要存哪些数据(名字、类型),edit 函数里用 props.attributes 读取当前值、用 props.setAttributes() 更新值,save 函数里同样用 props.attributes 把值填进最终输出的 HTML。做出两个可输入文字的框(天空颜色、草地颜色),编辑器里输入的内容会实时同步进 attributes,最终拼成一句「今天天空是 XX 色,草是 XX 色」的话存进数据库。顺带介绍了 attributes 的两种存储方式:默认存在 HTML 注释里,或者用 source/selector 从保存的 HTML 结构本身解析出来——作者明确表示自己偏好前者,只是作为知识点介绍后者。
涉及文件
wp-content/plugins/are-you-paying-attention/src/index.js(修改)
代码实现
src/index.js(完整文件,最终版本——默认的注释存储方式,未使用 source/selector):
wp.blocks.registerBlockType("ourplugin/are-you-paying-attention", {
title: "Are You Paying Attention?",
icon: "smiley",
category: "common",
attributes: {
skyColor: {type: "string"},
grassColor: {type: "string"}
},
edit: function (props) {
function updateSkyColor(event) {
props.setAttributes({skyColor: event.target.value})
}
function updateGrassColor(event) {
props.setAttributes({grassColor: event.target.value})
}
return (
<div>
<input type="text" placeholder="sky color" value={props.attributes.skyColor} onChange={updateSkyColor} />
<input type="text" placeholder="grass color" value={props.attributes.grassColor} onChange={updateGrassColor} />
</div>
)
},
save: function (props) {
return (
<p>Today the sky is <span className="skyColor">{props.attributes.skyColor}</span> and the grass is <span className="grassColor">{props.attributes.grassColor}</span>.</p>
)
}
})
关键改动点:
attributes: { skyColor: {type: "string"}, grassColor: {type: "string"} }:给 Block 声明两个数据字段,type是唯一必填的描述属性(还可以是array/number/boolean等),这是edit和save两个函数之间共享数据的「公共接口」edit(props):WordPress 调用这个函数时会自动传入一个props(属性)对象,里面包含props.attributes(当前所有属性的值)和props.setAttributes()(更新属性值的方法)——这是 Gutenberg/React 的标准约定,参数名props是业界惯例,不是强制要求但建议遵守onChange={updateSkyColor}:JSX 里绑定事件监听器的写法是on事件名={函数引用},属性名要用大写开头的驼峰(onChange而不是onchange);每次用户在输入框里打一个字都会触发这个函数updateSkyColor(event):浏览器/React 会自动把「这次事件的详细信息」作为参数传入回调函数,event.target是触发事件的那个 DOM 元素(这里是输入框本身),event.target.value就是用户当前打进去的完整文本props.setAttributes({skyColor: event.target.value}):调用这个方法、传入一个对象,WordPress 会把这个对象合并进现有的 attributes(不会影响其他没提到的属性),从而触发编辑器重新渲染、界面同步更新value={props.attributes.skyColor}:给输入框加上value属性、绑定到 attributes 里的值——这一步是让「刷新页面后重新打开编辑器,之前输入的内容依然显示在输入框里」的关键,光有onChange只能捕获输入但不会自动回显save(props)同样接收props,直接引用props.attributes.skyColor/props.attributes.grassColor把值嵌进最终输出的静态 HTML 里,{}是 JSX 里插入动态 JS 表达式的标准写法- JSX 里的 class 属性要写成
className(不能写class),因为class在 JavaScript 里是保留关键字,会跟 ES6 的class语法冲突 - 数据存储的两种方式:默认方式(这一讲最终采用的)——WordPress 会把整个
attributes对象序列化后存进一段 HTML 注释里,跟在保存的 HTML 内容前面,前台渲染不需要解析这段注释,只需要注释里的数据在编辑器重新打开时把值读回来;source+selector方式(作者展示但明确表示自己不常用)——不额外存注释,而是让「保存的 HTML 结构本身」成为唯一数据来源,靠 CSS 选择器(比如.skyColor)从已保存的 HTML 里重新解析出属性值,作者认为默认方式更直观、够用
[截图:Block 编辑器里两个可输入的文字框(sky color / grass color)及保存后前台显示的 "Today the sky is XX and the grass is XX." 效果]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
attributes(Block 配置属性) | Gutenberg Block API | 声明 Block 需要存储的数据字段及类型 |
props.attributes | Gutenberg 传入 edit/save 的参数 | 读取当前 Block 实例的属性值 |
props.setAttributes(obj) | Gutenberg 传入 edit 的方法 | 合并更新属性值,触发编辑器重新渲染 |
event.target.value | 浏览器原生 DOM API | 获取触发事件的表单元素当前的值 |
常见坑
- 输入框只写
onChange不写value——用户输入能被捕获、存进 attributes,但刷新页面重新打开编辑器时输入框会显示为空,因为没有告诉 React 用 attributes 里的值回显 - 修改了
save函数生成的 HTML 结构(比如加/删标签、改 attributes 定义)之后,已经插入文章里的旧 Block 实例会报「非预期或无效内容」的错误——这是因为编辑器发现数据库存的旧 HTML 跟当前save函数会生成的新 HTML 对不上,这一讲的临时解法是删除旧实例、重新插入新的,更规范的处理方式后面讲座会讲到 - 属性名用
class而不是className——JSX 里这是硬性规则,用错会导致编译报错或属性不生效
延伸 / 后续讲座会用到
现在的 Block 保存的都是「静态字符串」,下一讲要处理更复杂的场景:如果 Block 的内容需要在服务端用 PHP 动态生成(比如实时查询数据库),静态保存的字符串就不够用了——这是接下来要解决的问题。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 24, EP137