EP141. “Quiz Block 骨架:WordPress 内建组件与 SCSS”
🔒 登录后可标记已读📌 并入 EP140 的提醒:这一章录制完不久后,WordPress 官方改成推荐用 block.json 文件来声明/加载 Block 的 JS、CSS 资源。这不影响本章接下来教的「怎么写 Block 本身」的任何技巧,纯粹是加载资源文件的方式有新旧两种写法——本章后面会补一讲专门讲 block.json 的新写法,两种做法都合法,新写法只是官方现在更推荐的「标准姿势」。
开始做真正会用到的 Block——多选题问答(Quiz)。这一讲先把界面骨架搭出来,重点是尽量用 WordPress 自带的组件(@wordpress/components 包里的 TextControl、Flex、Button、Icon 等)而不是从零手写 HTML+CSS,好处是不用自己写样式就能获得跟 WordPress 后台一致的视觉效果。同时把 edit 函数抽成独立的具名组件(EditComponent),并引入 SCSS 文件写少量自定义样式。
涉及文件
wp-content/plugins/are-you-paying-attention/src/index.js(修改)wp-content/plugins/are-you-paying-attention/src/index.scss(新建)wp-content/plugins/are-you-paying-attention/index.php(修改)
代码实现
src/index.js:把 edit 抽成独立组件,用内建组件搭界面骨架:
import "./index.scss"
import {TextControl, Flex, FlexBlock, FlexItem, Button, Icon} from "@wordpress/components"
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: EditComponent,
save: function (props) {
return null
}
})
function EditComponent (props) {
function updateSkyColor(event) {
props.setAttributes({skyColor: event.target.value})
}
function updateGrassColor(event) {
props.setAttributes({grassColor: event.target.value})
}
return (
<div className="paying-attention-edit-block">
<TextControl label="Question:" />
<p>Answers:</p>
<Flex>
<FlexBlock>
<TextControl />
</FlexBlock>
<FlexItem>
<Button>
<Icon icon="star-empty" />
</Button>
</FlexItem>
<FlexItem>
<Button>Delete</Button>
</FlexItem>
</Flex>
</div>
)
}
src/index.scss(新建):
.paying-attention-edit-block {
padding: 20px;
border-radius: 2px;
border: 1px solid #f1f1f1;
background-color: #d6d6d6;
}
index.php:注册并挂载编辑器专属的 CSS:
function adminAssets() {
wp_register_style('quizeditcss', plugin_dir_url(__FILE__) . 'build/index.css');
wp_register_script('ournewblocktype', plugin_dir_url(__FILE__) . 'build/index.js', array('wp-blocks', 'wp-element', 'wp-editor'));
register_block_type('ourplugin/are-you-paying-attention', array(
'editor_script' => 'ournewblocktype',
'editor_style' => 'quizeditcss',
'render_callback' => array($this, 'theHTML')
));
}
关键改动点:
edit: EditComponent:把原本直接写在配置对象里的匿名函数,抽成文件底部一个独立、具名的函数。React 的约定是组件名要大写字母开头(EditComponent而不是editComponent),这样 React 才能区分「这是一个自定义组件」还是「这是一个普通 HTML 标签」import {TextControl, Flex, ...} from "@wordpress/components":不需要额外执行npm install就能直接导入——@wordpress/scripts内部的构建配置认识@wordpress/*这类包名,遇到时会自动转换成「去浏览器全局作用域里找 WordPress 已经加载好的对应模块」,而不是打包进产物里。React 和 ReactDOM 也是同样处理,避免打包出重复的 React 副本增加访问者的下载体积- 光
import组件还不够,还要在 PHP 里给依赖数组加上wp-editor——@wordpress/components这些包实际运行时依赖 WordPress 提供的wp-editor等脚本先加载好,缺了会在浏览器报错说找不到对应的全局对象 TextControl(文字输入框)、Flex/FlexBlock/FlexItem(弹性布局容器,FlexBlock会尽量占满可用空间,FlexItem只占自己需要的最小空间)、Button、Icon(配合内建 dashicon 名称如star-empty使用)——这些组件在这个阶段只是拿来摆架子,还没有接上任何真实的交互逻辑,纯粹练习「用现成组件代替手写 HTML/CSS 能省多少事」- SCSS 文件直接
import "./index.scss"到 JS 文件顶部,@wordpress/scripts会自动识别并把编译后的纯 CSS 抽取到build/index.css,不需要任何额外配置——跟前面「零配置支持 JSX」是同一套理念 - PHP 侧用
wp_register_style()注册 CSS 文件(不带依赖数组,因为纯 CSS 不需要依赖其他资源),再通过register_block_type()的editor_style参数把它跟 Block 关联起来,只在编辑器页面加载这份样式
[截图:Gutenberg 编辑器里插入 Quiz Block 后的骨架界面,含问题输入框、答案输入行、星标按钮和 Delete 按钮]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
@wordpress/components | WordPress 官方 JS 包 | 提供一整套跟 WordPress 后台视觉风格一致的现成 UI 组件(输入框、按钮、布局容器等) |
wp-editor(脚本依赖名) | WP 内建脚本句柄 | @wordpress/components 等编辑器相关包的运行时依赖 |
wp_register_style($handle, $src) | WP 内建 function | 注册(不立即加载)一个 CSS 文件 |
editor_style(register_block_type 参数) | Gutenberg Block API | 指定该 Block 在编辑器里需要加载的 CSS |
常见坑
import了@wordpress/components却忘记在 PHP 依赖数组里加wp-editor——编辑器页面会直接报 JS 错误,因为浏览器全局作用域里找不到对应模块- React 组件函数名用小写开头——React 会把它当成普通 HTML 标签名处理而不是自定义组件,导致渲染出错或出现意外行为
- 手写一整套 HTML+CSS 来实现 WordPress 已经提供现成组件的效果——多做了不必要的工作,还可能跟后台整体视觉风格不一致
延伸 / 后续讲座会用到
下一讲继续微调样式,让界面更接近最终效果,然后开始写 JavaScript 让「新增答案行」「标记正确答案」「删除答案行」这些交互真正动起来。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 25, EP141(含 EP140 提醒并入)