自定义字段
🌐 Custom Fields
Page summary:自定义字段通过新的字段类型扩展 Strapi,这些字段在内容类型构建 器和内容管理器中表现得像原生字段。本文档中的说明涵盖了通过插件构建或安装字段以及以编程方式注册字段的步骤。
自定义字段通过向内容类型和组件添加新类型的字段来扩展 Strapi 的功能。一旦通过插件创建或添加到 Strapi,自定义字段就可以像内置字段一样在内容类型构建器和内容管理器中使用。
🌐 Custom fields extend Strapi’s capabilities by adding new types of fields to content-types and components. Once created or added to Strapi via plugins, custom fields can be used in the Content-Type Builder and Content Manager just like built-in fields.
配置
🌐 Configuration
现成的自定义字段可以在 Marketplace 中找到。安装后,无需其他配置,即可开始使用它们(参见 使用方法)。
🌐 Ready-made custom fields can be found on the Marketplace. Once installed these, no other configuration is required, and you can start using them (see usage).
你也可以开发自己的自定义字段。
🌐 You can also develop your own custom field.
开发你自己的自定义字段
🌐 Developing your own custom field
虽然推荐的添加自定义字段的方法是通过创建插件,但特定应用的自定义字段也可以在 src/index 和 src/admin/app 文件中找到的全局 register 函数 中注册。
🌐 Though the recommended way to add a custom field is through creating a plugin, app-specific custom fields can also be registered within the global register function found in src/index and src/admin/app files.
- 自定义字段只能使用插件在 Marketplace 上共享和分发。
- 自定义字段不能为 Strapi 添加新的数据类型,必须使用在 模型属性 文档中描述的现有内置 Strapi 数据类型。
- 你也无法修改现有的数据类型。
- Strapi 特有的特殊数据类型(例如关系、媒体、组件或动态区域数据类型)不能在自定义字段中使用。
通过插件注册自定义字段需要创建并启用一个插件(参见 插件开发)。
🌐 Registering a custom field through a plugin requires creating and enabling a plugin (see Plugins development).
自定义字段插件包括服务器和管理面板部分。自定义字段必须在两个部分都注册,才能在 Strapi 的管理面板中使用。
🌐 Custom field plugins include both a server and admin panel part. The custom field must be registered in both parts before it is usable in Strapi's admin panel.
在服务器上注册自定义字段
🌐 Registering a custom field on the server
Strapi 的服务器需要了解所有自定义字段,以确保使用自定义字段的属性有效。
🌐 Strapi's server needs to be aware of all the custom fields to ensure that an attribute using a custom field is valid.
strapi.customFields 对象在 Strapi 实例上公开了一个 register() 方法。此方法用于在插件的服务器 注册生命周期 期间在服务器上注册自定义字段。
🌐 The strapi.customFields object exposes a register() method on the Strapi instance. This method is used to register custom fields on the server during the plugin's server register lifecycle.
strapi.customFields.register() 通过传递一个对象(或对象数组)以及一些参数,在服务器上注册一个或多个自定义字段。
可用于在服务器上注册自定义字段的参数:
| 参数 | 描述 | 类型 |
|---|---|---|
name | 自定义字段的名称 | String |
plugin(可选) | 创建自定义字段的插件名称 ❗️ 如果定义了,则管理面板注册的 pluginId 值必须与其相同(参见 在管理面板注册自定义字段) | String |
type | 自定义字段将使用的数据类型 | String |
inputSize(可选) | 用于定义管理面板中自定义字段输入宽度的参数 | Object |
可选的 inputSize 对象,如果指定,必须包含以下所有参数:
🌐 The optional inputSize object, when specified, must contain all of the following parameters:
| 参数 | 描述 | 类型 |
|---|---|---|
default | 在管理面板的 12 列网格中,输入字段默认占用的列数。 值可以是 4、6、8 或 12。 | Integer |
isResizable | 输入是否可以调整大小 | Boolean |
示例:在服务器上注册一个示例“颜色”自定义字段:
在以下示例中,color-picker 插件是使用 CLI 生成器创建的(参见 插件开发):
🌐 In the following example, the color-picker plugin was created using the CLI generator (see plugins development):
- JavaScript
- TypeScript
module.exports = ({ strapi }) => {
strapi.customFields.register({
name: "color",
plugin: "color-picker",
type: "string",
inputSize: {
// optional
default: 4,
isResizable: true,
},
});
};
export default ({ strapi }: { strapi: any }) => {
strapi.customFields.register({
name: "color",
plugin: "color-picker",
type: "string",
inputSize: {
// optional
default: 4,
isResizable: true,
},
});
};
如果你没有使用 CLI 生成器生成插件代码,该自定义字段也可以直接在 strapi-server.js 文件中声明:
🌐 The custom field could also be declared directly within the strapi-server.js file if you didn't have the plugin code scaffolded by the CLI generator:
- JavaScript
- TypeScript
module.exports = {
register({ strapi }) {
strapi.customFields.register({
name: "color",
plugin: "color-picker",
type: "text",
inputSize: {
// optional
default: 4,
isResizable: true,
},
});
},
};
export default {
register({ strapi }: { strapi: any }) {
strapi.customFields.register({
name: "color",
plugin: "color-picker",
type: "text",
inputSize: {
// optional
default: 4,
isResizable: true,
},
});
},
};
在管理面板中注册自定义字段
🌐 Registering a custom field in the admin panel
通过插件注册自定义字段需要创建并启用一个插件(参见 插件开发)。
🌐 Registering a custom field through a plugin requires creating and enabling a plugin (see Plugins development).
自定义字段必须在 Strapi 的管理面板中注册,才能在内容类型生成器和内容管理器中使用。
🌐 Custom fields must be registered in Strapi's admin panel to be available in the Content-type Builder and the Content Manager.
app.customFields 对象在 StrapiApp 实例上暴露了一个 register() 方法。此方法用于在插件的管理员 注册生命周期 中注册自定义字段。
🌐 The app.customFields object exposes a register() method on the StrapiApp instance. This method is used to register custom fields in the admin panel during the plugin's admin register lifecycle.
app.customFields.register() 通过传递一个带有某些参数的对象(或对象数组)在管理面板中注册一个或多个自定义字段。
可用于在服务器上注册自定义字段的参数:
| 参数 | 描述 | 类型 |
|---|---|---|
name | 自定义字段名称 | String |
pluginId(可选) | 创建自定义字段的插件名称 ❗️ 如果已定义,服务器注册时的 plugin 值必须与之相同(见 在服务器上注册自定义字段) | String |
type | 自定义字段将使用的现有 Strapi 数据类型 ❗️ 不能使用关系、媒体、组件或动态区域。 | String |
icon(可选) | 自定义字段的图标 | React.ComponentType |
intlLabel | 名称的翻译 | IntlObject |
intlDescription | 描述的翻译 | IntlObject |
components | 在内容管理器中显示自定义字段所需的组件(参见 components) | |
options(可选) | 由内容类型构建器使用的选项(参见 选项) | Object |
示例:在管理面板中注册一个示例“颜色”自定义字段:
在以下示例中,color-picker 插件是使用 CLI 生成器创建的(参见 插件开发):
🌐 In the following example, the color-picker plugin was created using the CLI generator (see plugins development):
- JavaScript
- TypeScript
import ColorPickerIcon from "./components/ColorPicker/ColorPickerIcon";
export default {
register(app) {
// ... app.addMenuLink() goes here
// ... app.registerPlugin() goes here
app.customFields.register({
name: "color",
pluginId: "color-picker", // the custom field is created by a color-picker plugin
type: "string", // the color will be stored as a string
intlLabel: {
id: "color-picker.color.label",
defaultMessage: "Color",
},
intlDescription: {
id: "color-picker.color.description",
defaultMessage: "Select any color",
},
icon: ColorPickerIcon, // don't forget to create/import your icon component
components: {
Input: async () =>
import('./components/Input').then((module) => ({
default: module.Input,
})),
},
options: {
// declare options here
},
});
},
// ... bootstrap() goes here
};
import ColorPickerIcon from "./components/ColorPicker/ColorPickerIcon";
export default {
register(app) {
// ... app.addMenuLink() goes here
// ... app.registerPlugin() goes here
app.customFields.register({
name: "color",
pluginId: "color-picker", // the custom field is created by a color-picker plugin
type: "string", // the color will be stored as a string
intlLabel: {
id: "color-picker.color.label",
defaultMessage: "Color",
},
intlDescription: {
id: "color-picker.color.description",
defaultMessage: "Select any color",
},
icon: ColorPickerIcon, // don't forget to create/import your icon component
components: {
Input: async () =>
import('./components/Input').then((module) => ({
default: module.Input,
})),
},
options: {
// declare options here
},
});
},
// ... bootstrap() goes here
};
组件
🌐 Components
app.customFields.register() 必须传递一个包含 Input React 组件的 components 对象,以在内容管理器的编辑视图中使用。
示例:注册一个输入组件:
在以下示例中,color-picker 插件是使用 CLI 生成器创建的(参见 插件开发):
🌐 In the following example, the color-picker plugin was created using the CLI generator (see plugins development):
- JavaScript
- TypeScript
export default {
register(app) {
app.customFields.register({
// …
components: {
Input: async () =>
import('./components/Input').then((module) => ({
default: module.Input,
})),
},
// …
});
},
};
export default {
register(app) {
app.customFields.register({
// …
components: {
Input: async () =>
import('./components/Input').then((module) => ({
default: module.Input,
})),
},
// …
});
},
};
传递给自定义字段 Input 组件的属性:
| 属性 | 描述 | 类型 |
|---|---|---|
attribute | 带有自定义字段的属性对象的底层 Strapi 类型和选项 | { type: String, customField: String } |
description | 在 配置视图 中设置的字段描述 | IntlObject |
placeholder | 在 配置视图 中设置的字段占位符 | IntlObject |
hint | 在 配置视图 中设置的字段描述,以及最小/最大 验证要求 | String |
name | 在内容类型构建器中设置的字段名称 | String |
intlLabel | 在内容类型构建器中设置的字段名称或配置视图 | IntlObject |
onChange | 输入变化事件的处理程序。name 参数引用字段名称。type 参数引用底层 Strapi 类型 | ({ target: { name: String value: unknown type: String } }) => void |
contentTypeUID | 字段所属的内容类型 | String |
type | 自定义字段 uid,例如 plugin::color-picker.color | String |
value | 底层 Strapi 类型期望的输入值 | unknown |
required | 该字段是否为必填 | boolean |
error | 验证后收到的错误 | IntlObject |
disabled | 输入是否被禁用 | boolean |
从 Strapi v4.13.0 开始,内容管理器中的字段可以通过 URLSearchParam field 自动获得焦点。建议你的输入组件被封装在 React 的 `forwardRef` 方法中;你应将对应的 ref 传递给 input 元素。
🌐 As of Strapi v4.13.0, fields in the Content Manager can be auto-focussed via the URLSearchParam field. It's recommended that your input component is wrapped in React's `forwardRef` method; you should pass the corresponding ref to the input element.
示例:自定义文本输入
在以下示例中,我们提供了一个受控的自定义文本输入。所有输入都应该是受控的,否则它们的数据在保存时将不会被提交。
🌐 In the following example we're providing a custom text input that is controlled. All inputs should be controlled otherwise their data will not be submitted on save.
- JavaScript
- TypeScript
import * as React from "react";
import { useIntl } from "react-intl";
const Input = React.forwardRef((props, ref) => {
const { attribute, disabled, intlLabel, name, onChange, required, value } =
props; // these are just some of the props passed by the content-manager
const { formatMessage } = useIntl();
const handleChange = (e) => {
onChange({
target: { name, type: attribute.type, value: e.currentTarget.value },
});
};
return (
<label>
{formatMessage(intlLabel)}
<input
ref={ref}
name={name}
disabled={disabled}
value={value}
required={required}
onChange={handleChange}
/>
</label>
);
});
export default Input;
import * as React from "react";
import { useIntl } from "react-intl";
const Input = React.forwardRef((props, ref) => {
const { attribute, disabled, intlLabel, name, onChange, required, value } =
props; // these are just some of the props passed by the content-manager
const { formatMessage } = useIntl();
const handleChange = (e) => {
onChange({
target: { name, type: attribute.type, value: e.currentTarget.value },
});
};
return (
<label>
{formatMessage(intlLabel)}
<input
ref={ref}
name={name}
disabled={disabled}
value={value}
required={required}
onChange={handleChange}
/>
</label>
);
});
export default Input;
要详细了解提供给 customFields 的 props 以及它们如何使用,请查看 Strapi 代码库中的 ColorPickerInput file 。
选项
🌐 Options
app.customFields.register() 可以传递一个额外的 options 对象,具有以下参数:
传递给自定义字段 options 对象的参数:
| 参数选项 | 描述 | 类型 |
|---|---|---|
base | 在内容类型构建器的字段的 基础设置 选项卡中可用的设置 | Object 或 Array of Objects |
advanced | 在内容类型构建器的字段的 高级设置 选项卡中可用的设置 | Object 或 Array of Objects |
validator | 返回对象的验证函数,用于清理输入。使用 `yup` schema object。 | Function |
base 和 advanced 设置都接受一个对象或对象数组,每个对象都是一个设置部分。每个设置部分可以包括:
🌐 Both base and advanced settings accept an object or an array of objects, each object being a settings section. Each settings section could include:
- 一个
sectionTitle用于将节的标题声明为一个 IntlObject - 以及一个将
items作为对象数组的列表。
items 数组中的每个对象可以包含以下参数:
🌐 Each object in the items array can contain the following parameters:
| 参数项 | 描述 | 类型 |
|---|---|---|
name | 输入的标签。 必须使用 options.settingName 格式。 | String |
description | 在内容类型构建器中使用的输入描述 | String |
intlLabel | 输入标签的翻译 | `IntlObject` |
type | 输入的类型(例如,select、checkbox) | String |
示例:为示例“颜色”自定义字段声明选项:
在以下示例中,color-picker 插件是使用 CLI 生成器创建的(参见 插件开发):
🌐 In the following example, the color-picker plugin was created using the CLI generator (see plugins development):
- JavaScript
- TypeScript
// imports go here (ColorPickerIcon, pluginId, yup package…)
export default {
register(app) {
// ... app.addMenuLink() goes here
// ... app.registerPlugin() goes here
app.customFields.register({
// …
options: {
base: [
/*
Declare settings to be added to the "Base settings" section
of the field in the Content-Type Builder
*/
{
sectionTitle: {
// Add a "Format" settings section
id: "color-picker.color.section.format",
defaultMessage: "Format",
},
items: [
// Add settings items to the section
{
/*
Add a "Color format" dropdown
to choose between 2 different format options
for the color value: hexadecimal or RGBA
*/
intlLabel: {
id: "color-picker.color.format.label",
defaultMessage: "Color format",
},
name: "options.format",
type: "select",
value: "hex", // option selected by default
options: [
// List all available "Color format" options
{
key: "hex",
defaultValue: "hex",
value: "hex",
metadatas: {
intlLabel: {
id: "color-picker.color.format.hex",
defaultMessage: "Hexadecimal",
},
},
},
{
key: "rgba",
value: "rgba",
metadatas: {
intlLabel: {
id: "color-picker.color.format.rgba",
defaultMessage: "RGBA",
},
},
},
],
},
],
},
],
advanced: [
/*
Declare settings to be added to the "Advanced settings" section
of the field in the Content-Type Builder
*/
],
validator: (args) => ({
format: yup.string().required({
id: "options.color-picker.format.error",
defaultMessage: "The color format is required",
}),
}),
},
});
},
};
// imports go here (ColorPickerIcon, pluginId, yup package…)
export default {
register(app) {
// ... app.addMenuLink() goes here
// ... app.registerPlugin() goes here
app.customFields.register({
// …
options: {
base: [
/*
Declare settings to be added to the "Base settings" section
of the field in the Content-Type Builder
*/
{
sectionTitle: {
// Add a "Format" settings section
id: "color-picker.color.section.format",
defaultMessage: "Format",
},
items: [
// Add settings items to the section
{
/*
Add a "Color format" dropdown
to choose between 2 different format options
for the color value: hexadecimal or RGBA
*/
intlLabel: {
id: "color-picker.color.format.label",
defaultMessage: "Color format",
},
name: "options.format",
type: "select",
value: "hex", // option selected by default
options: [
// List all available "Color format" options
{
key: "hex",
defaultValue: "hex",
value: "hex",
metadatas: {
intlLabel: {
id: "color-picker.color.format.hex",
defaultMessage: "Hexadecimal",
},
},
},
{
key: "rgba",
value: "rgba",
metadatas: {
intlLabel: {
id: "color-picker.color.format.rgba",
defaultMessage: "RGBA",
},
},
},
],
},
],
},
],
advanced: [
/*
Declare settings to be added to the "Advanced settings" section
of the field in the Content-Type Builder
*/
],
validator: (args) => ({
format: yup.string().required({
id: "options.color-picker.format.error",
defaultMessage: "The color format is required",
}),
}),
},
});
},
};
Strapi 代码库提供了一个示例,说明如何描述设置对象:查看 `baseForm.ts` 文件中的 base 设置,以及 `advancedForm.ts` 文件中的 advanced 设置。基础表单将设置项以内联方式列出,而高级表单则从 `attributeOptions.js` 文件中获取设置项。
🌐 The Strapi codebase gives an example of how settings objects can be described: check the `baseForm.ts` file for the base settings and the `advancedForm.ts` file for the advanced settings. The base form lists the settings items inline but the advanced form gets the items from an `attributeOptions.js` file.
使用
🌐 Usage
在管理面板中
🌐 In the admin panel
可以通过从 Marketplace 安装或创建自己的字段来向 Strapi 添加自定义字段。
🌐 Custom fields can be added to Strapi either by installing them from the Marketplace or by creating your own.
一旦添加到 Strapi,自定义字段可以添加到任何内容类型。选择内容类型的字段时,自定义字段会列在 Custom 选项卡中。
🌐 Once added to Strapi, custom fields can be added to any content type. Custom fields are listed in the Custom tab when selecting a field for a content-type.
每种自定义字段类型都可以有基本和高级设置。 Marketplace 列出可用的自定义字段,并为每个自定义字段提供专门的文档,包括具体设置。
在代码中
🌐 In the code
创建和使用后,自定义字段的定义就像模型架构中的任何其他属性一样。
🌐 Once created and used, custom fields are defined like any other attribute in the model's schema.
自定义字段在模型的属性中使用 type: customField 明确定义。
🌐 Custom fields are explicitly defined in the attributes of a model with type: customField.
与其他类型的模型定义方式相比,自定义字段的属性还具有以下特性:
🌐 As compared to how other types of models are defined, custom fields' attributes also show the following specificities:
-
自定义字段具有
customField属性。其值充当唯一标识符,用于指示应使用哪个已注册的自定义字段,并遵循以下两种格式之一:格式 来源 plugin::plugin-name.field-name自定义字段是通过插件创建的 global::field-name自定义字段特定于当前 Strapi 应用,并且是直接在 register函数 中创建的
示例:一个简单的 color 自定义字段模型定义:
{
// …
"attributes": {
"color": { // name of the custom field defined in the Content-Type Builder
"type": "customField",
"customField": "plugin::color-picker.color",
"options": {
"format": "hex"
}
}
}
// …
}
存储结构化 JSON 的自定义字段可以成为深层嵌套关系结构的高性能替代方案。当数据无需独立查询时,将其存储为单个 JSON 字段可以避免昂贵的联接。详见 Strapi 博客上的 Building High-Performance Strapi Applications 。