社区新闻

为区块添加自定义颜色选项的逐步指南

查看官方原文 ↗ 发布于

想象一下:你正在愉快地为你梦想已久的区块编写代码。几乎所有元素和设置都已就位。你已接近终点线,准备将这个作品发布到世界。

但有一件事缺失了:你需要一个额外的颜色设置。

你已经实现了WordPress为区块开发者开箱即用的标准文本、背景和链接颜色。但你的区块很特别。它至少还需要一种颜色,这样你的用户才能享受到你在开始这段旅程时所设想的终极可定制性。

但有一个问题:WordPress没有一种简单的方法来配置一个颜色属性,使其能神奇地为你的区块工作(如果真有就太酷了)。你突然需要编写所有这些代码。

本教程将为你提供一个为区块添加自定义颜色选项的解决方案。

需要提前了解的事项

这是一个高级教程,因此我对你的知识水平做了一些假设。这对于将本文控制在合理的字数内是必要的。

具体来说,我做了两个主要假设:

  • 你已经知道如何从头开始构建自定义区块,并且会使用@wordpress/scripts包。
  • 你足够熟练,能够将本指南中学到的知识应用到自定义用例中。

如果你还没有达到这个水平,需要更多帮助,请跳转到区块编辑器手册,并从其可用指南开始学习。当你觉得自己准备好学习本教程时,它仍然会在这里等着你。

你可以在其GitHub仓库中查看我为编写本教程而构建的示例区块。我不会解释每一个细节——记住,我假设你有一些先验知识。但代码可供你随意使用。

本教程中的代码使用了WordPress中的实验性功能。这绝对意味着它们可能——而且很可能会——在某个时候失效。如果你不喜欢生活在技术前沿,这可能不适合你。但如果你像我一样喜欢修复损坏的东西,请记住,如果你决定在生产中使用此代码,并且它将来停止工作,你最终需要负责更新你的插件、主题或网站。

构建带有彩色标记的列表区块

在接下来的部分中,你将学习如何为一个输出基本HTML列表的区块添加自定义标记颜色选项,如下所示:

WordPress文章编辑器,内容区域有一个自定义列表区块。侧边栏中有一个名为Marker的颜色选项,其选择器已弹出。

毫无疑问,你会想将此应用到你正在构建的自己的区块中,因此请随意在阅读时挑选你需要的部分。但按照步骤构建这个更简单的区块也是一个很好的练习。

设置你的区块插件

在本教程中,示例将在静态区块中展示,但你也可以将它们应用于动态区块。它遵循@wordpress/create-block@wordpress/scripts包提供的标准文件和文件夹命名约定。

你的插件文件结构应为:

  • build/
    • WordPress会将编译后的文件输出到此文件夹。
  • src/
    • block.json
    • edit.js
    • index.js
    • save.js
    • style.scss
  • index.php

首先,添加你的插件文件头,并在init钩子上使用register_block_type()函数注册区块:

<?php
/**
 * Plugin Name:       List Block With Marker Colors
 * Plugin URI:        https://developer.wordpress.org/news/
 * Description:       An example block that shows a list with a custom marker color option.
 * Version:           1.0.0
 * Requires at least: 6.3
 * Requires PHP:      7.4
 * Author:            WordPress Developer Blog
 * Author URI:        https://developer.wordpress.org/news/
 * Text Domain:       devblog
 */

add_action( 'init', 'devblog_list_marker_colors_setup' );

function devblog_list_marker_colors_setup() {
	register_block_type( trailingslashit( __DIR__ ) . 'build' );
}

向block.json添加颜色属性

添加自定义颜色选项时,应始终注意开箱即用的现有功能。WordPress具有用于处理以下内容的属性:

  • 文本颜色
  • 链接文本颜色
  • 背景颜色和渐变
  • 边框颜色(通过border支持而非color处理)

只有在无法使用默认值的情况下,添加新的颜色属性才有意义。请记住,你可以使用选择器API将现有颜色属性应用于区块的特定选择器。

对于我们虚构的列表区块,让我们添加一个颜色选项,允许用户更改列表标记(项目符号)颜色。 

为此,你需要两个新的属性

  • markerColor(字符串)用于存储用户选择预设颜色时的slug。
  • customMarkerColor(字符串)用于保存预设颜色或用户选择自定义颜色时的CSS颜色值。

从技术上讲,你可以使用单个属性,并在幕后添加一些自定义逻辑来处理预设和自定义颜色。但使用两个独立的属性可以使代码库更简单。一旦你开始为自己的区块自定义此功能,你可能会发现有很多不同的方法来解决这个问题。

在你的block.json文件中,将markerColorcustomMarkerColor属性添加到attributes对象中:

{
	"apiVersion": 3,
	"version": "1.0.0",
	"name": "devblog/list-with-marker-colors",
	"title": "List With Marker Colors",
	"category": "widgets",
	"description": "Add a custom description here.",
	"attributes" : {
		"markerColor": {
			"type": "string"
		},
		"customMarkerColor": {
			"type": "string"
		}
	},
	"supports": {
		"color": {
			"link": true,
			"gradients": true
		}
	},
	"textdomain": "devblog",
	"editorScript": "file:./index.js",
	"style": "file:./style-index.css",
	"example": {}
}

构建区块编辑函数

完成所有初始设置和block.json代码后,是时候进入本教程的核心部分,为你的区块类型添加自定义控件了。这就是你来这里的目的,对吧?

在以下小节中,你将直接在区块的edit.js文件中工作。

导入依赖项

在编写任何自定义代码之前,你需要从@wordpress/block-editor@wordpress/i18n包中导入几个依赖项。你应该已经熟悉其中的大多数,但特定于颜色的组件对你来说可能是新的:

  • withColors
  • __experimentalColorGradientSettingsDropdown
  • __experimentalUseMultipleOriginColorsAndGradients

我们将在接下来的部分中深入探讨它们的工作原理。现在,你只需要在edit.js文件的顶部导入它们:

import {
	InspectorControls,
	useBlockProps,
	withColors,
	__experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
	__experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients
} from '@wordpress/block-editor';

import { __ } from '@wordpress/i18n';

该代码为实验性组件名称使用了别名,去掉了__experimental前缀。这是标准做法,这样当组件不再是实验性时,你只需要更改导入代码本身。

编写区块编辑函数

添加导入后,你需要一个区块编辑函数来处理编辑器中的功能。为此,将以下代码添加到区块的edit.js文件中:

const Edit = ( {
	attributes: {
		customMarkerColor
	},
	markerColor,
	setMarkerColor,
	setAttributes,
	style,
	clientId
} ) => {
	// Add your custom code here.
};

export default withColors( {
	markerColor: 'marker-color'
} )( Edit );

你可能会注意到markerColor没有嵌套在attributes属性下。它是一个完全独立的属性,并且有一个伴随的setMarkerColor。这是因为编辑函数被withColors高阶组件包装了。这为你提供了特定的属性,以便更高效地处理颜色。

markerColor现在是一个对象,你可以访问它的几个属性,而不是一个字符串。以下是选择预设颜色时该对象的示例:

{
	class: "has-vivid-red-marker-color",
	color: "#cf2e2e",
	name: "Vivid red",
	slug: "vivid-red"
}

但当选择自定义颜色时,它看起来像这样:

{
	class: undefined,
	color: "#66b3dc"
}

你可以使用这些数据来做各种巧妙的事情,例如将类添加到区块包装器,或者操作slug来做一些自定义的事情。

setMarkerColor是一个为列表设置新标记颜色的函数。它是由传递给withColorsmarkerColor名称加上前缀set构建而成的。

现在让我们开始构建Edit()函数的核心。本节中剩余的代码片段应放在函数内部。

你首先需要获取的是WordPress颜色和渐变设置的副本。这使用了useMultipleOriginColorsAndGradients()(实验性)React钩子。它为你提供了一个对象,其中包含你的颜色控件所需的大部分设置,包括WordPress、主题和用户定义的颜色和渐变数组。

将此代码添加到区块的Edit()函数中:

const colorGradientSettings = useMultipleOriginColorsAndGradients();

接下来,你将把useBlockProps()钩子赋值给blockProps常量。但你也会利用这个机会添加输出标记颜色的逻辑。

为此,你将操作区块的style属性。由于此特定场景将针对列表标记,下面的代码使用了一个名为--devblog-list-markerCSS自定义属性,并为其分配标记颜色。

将此代码添加到区块的Edit()函数中:

const blockProps = useBlockProps( {
	style: {
		...style,
		'--devblog-list-marker': markerColor.slug
			    ? `var( --wp--preset--color--${ markerColor.slug } )`
			    : customMarkerColor,
	}
} );

现在是时候添加自定义颜色控件了。为此,你需要ColorGradientSettingsDropdown(实验性)组件。实际上,此时你主要做的就是插入一些值。

将此代码添加到区块的Edit()函数中:

const markerColorDropdown = (
	<ColorGradientSettingsDropdown
		settings={ [ {
			label: __( 'Marker', 'devblog' ),
			colorValue: markerColor.color || customMarkerColor,
			onColorChange: ( value ) => {
				setMarkerColor( value );

				setAttributes( {
					customMarkerColor: value
				} );
			}
		} ] }
		panelId={ clientId }
		hasColorsOrGradients={ false }
		disableCustomColors={ false }
		__experimentalIsRenderedInSidebar
		{ ...colorGradientSettings }
	/>
);

我想提请你注意该组件的两个属性:

  • colorValue对于此处的值,请确保检查markerColor.colorcustomMarkerColor
  • onColorChange你需要同时调用setMarkerColor()(用于设置markerColor属性)和setAttributes(用于设置customMarkerColor属性)。

最后一项是返回区块控件和标记。对于此区块类型,为了演示目的,我将其保留为一个简单的无序列表。你显然希望将此技术应用于更复杂的区块。

现在将此最后一段代码添加到区块的Edit()函数中:

return (
	<>
		<InspectorControls group="color">
			{ markerColorDropdown }
		</InspectorControls>
		<ul { ...blockProps }>
			<li>{ __( 'List Item 1', 'devblog' ) }</li>
			<li>{ __( 'List Item 2', 'devblog' ) }</li>
			<li>{ __( 'List Item 3', 'devblog' ) }</li>
			<li>{ __( 'List Item 4', 'devblog' ) }</li>
			<li>{ __( 'List Item 5', 'devblog' ) }</li>
		</ul>
	</>
);

关于这段代码需要注意的一点是<InspectorControls>group属性。通过赋予它color值,你告诉WordPress将你的标记颜色选择器与区块侧边栏中的所有其他颜色设置放在一起。要了解更多关于其工作原理的信息,请查看使用区块检查器侧边栏分组

构建区块保存函数

由于这是一个静态区块,我们还需要在后端保存区块标记。如果你正在构建一个动态区块,你将在PHP端添加你的处理。

在以下小节中,你将在区块的save.js文件中工作。

导入依赖项

像往常一样,你需要为保存函数导入一些依赖项。同样,你需要从@wordpress/block-editor@wordpress/i18n包中获取一些东西。

将此代码添加到区块save.js文件的顶部:

import { useBlockProps } from '@wordpress/block-editor';
import { __ }            from '@wordpress/i18n';

导出保存函数

保存函数比上一节的编辑函数简单得多。为此,你基本上只需要导出区块的最终标记,以便将其存储在数据库中。

这里的主要区别是你需要markerColorcustomMarkerColor两个属性。正如在block.json中定义的,每个都将是一个字符串值。

将此代码添加到你的save.js文件中:

export default function Save( {
	attributes: {
		markerColor,
		customMarkerColor
	},
	style
} ) {

	const blockProps = useBlockProps.save( {
		style: {
			...style,
			'--devblog-list-marker': markerColor !== undefined
			            ? `var( --wp--preset--color--${ markerColor } )`
				    : customMarkerColor,
		}
	} );

	return (
		<ul { ...blockProps }>
			<li>{ __( 'List Item 1', 'devblog' ) }</li>
			<li>{ __( 'List Item 2', 'devblog' ) }</li>
			<li>{ __( 'List Item 3', 'devblog' ) }</li>
			<li>{ __( 'List Item 4', 'devblog' ) }</li>
			<li>{ __( 'List Item 5', 'devblog' ) }</li>
		</ul>
	);
}

添加自定义样式

由于区块使用--devblog-list-marker CSS自定义属性来处理列表标记颜色,它需要一种方法来告诉浏览器显示该颜色。为此,你需要在CSS中定位区块的任何::marker伪元素。

将此添加到区块的style.scss文件中:

.