Directus Interfaces 接口开发指南:深入解析 defineInterface 的字段编辑组件体系
【免费下载链接】directusThe flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.项目地址: https://gitcode.com/GitHub_Trending/di/directus
Interfaces(接口组件)是 Directus 管理后台中负责编辑与查看单条数据的原子化组件,它们构成了表单中的一个个字段输入区。本指南以app/src/interfaces/readme.md的官方说明为骨架,结合仓库内defineInterface的类型定义与input、boolean等真实实现,带你在该开源仓库中理解 Directus 接口组件的结构、注册契约与选项声明方式,最终掌握如何用 Vue 组件 + 配置元数据构建出可复用的自定义字段编辑控件。
什么是 Directus Interfaces
Interfaces 是 Directus 生态中与 Displays、Layouts、Modules 并列的四大 App 扩展点之一,其定位可以用一句话概括:接口组件是允许你编辑和查看某一条数据的独立输入块。
在界面上的直观表现是:表单中的每个字段都是一次 Interfaces 的渲染,正如官方文档所说:
Interfaces can be seen as the individual fields in a form, where the field is a single column in a table.
即表单中的"字段" ↔ 表中的"列",而"接口组件"就是承载这一列的编辑 UI。整个接口目录位于仓库的 app/src/interfaces,其中包含了input(文本/数字输入)、boolean(开关)、select-dropdown、list-m2m、file-image、map等约 40 个面向用户的接口组件,以及一组以_system前缀命名的系统内部接口(如_system/system-field、_system/system-permissions等),后者用于 Directus 自身的系统字段配置界面。
定义接口的起点:defineInterface
任何接口都必须通过defineInterface函数来声明注册,借助它,接口可以将自己的名称、图标、输入组件和可选参数统一"挂载"到 Directus 的字段配置体系中。官方文档给出了这样一个示例骨架:
export default defineInterface({ id: 'input', register: ({ i18n }) => ({ name: i18n.global.t('input'), icon: 'box', component: InterfaceTextInput, }), });需要特别说明的是:上述register回调式写法来自官方旧版说明。从当前仓库的实际源码看,接口配置已经演进为直接在配置对象顶层声明name、icon、component、types、group、options等属性的扁平形态(见下文各节对照)。无论形式如何变化,其注册机制的本质没有变——defineInterface本身是一个类型辅助的身份函数(identity function),它的实现位于 packages/extensions/src/shared/utils/define-extension.ts#L18-L22,接收配置对象后原样返回并补全类型约束:
export function defineInterface<Custom extends CustomConfig<InterfaceConfig>>( config: ExtendedConfig<InterfaceConfig, Custom>, ): ExtendedConfig<InterfaceConfig, Custom> { return config; }对应的单测 packages/extensions/src/shared/utils/define-extension.test.ts 也验证了这一点:expect(defineInterface(interfaceConfig)).toBe(interfaceConfig)。它的作用是让编辑器在编写配置时获得完整的字段类型提示与校验,并在需要时允许附带自定义扩展属性。接口的完整配置契约定义在 packages/types/src/extensions/interfaces.ts 的InterfaceConfig接口中。
接口元数据字段逐一解析
id
id是接口在平台内的唯一标识。它不会直接展示给最终用户,而是被内部用来构建表单与布局——例如某接口的options配置在描述自身设置项时,会通过interface: 'select-icon'、interface: 'select-color'这类字符串反向引用其它接口作为设置项控件,这些字符串对应的正是被引用接口的id。
官方文档同时以id: 'input'作为示例:在源码中,input接口的实际配置位于 app/src/interfaces/input/index.ts,boolean接口则使用id: 'boolean'(见 app/src/interfaces/boolean/index.ts)。在编写自定义接口时,请务必保证id在平台内全局唯一,避免与内置或第三方接口冲突。
register与 context(含 i18n)
在官方文档描述的旧式 API 中,register是一个回调函数,用于注册接口的选项与其他面向用户的参数。回调唯一接收的参数是context,其承载内容如下:
| 属性 | 说明 |
|---|---|
i18n | Directus 内部集成的 vue-i18n 实例,可用于返回翻译后的接口名称或翻译后的接口选项文本 |
而如前所述,当前仓库中的InterfaceConfig已将所有元数据收敛为顶层属性,name、icon、component、options均直接声明,不再经由register包裹。现代配置中的名称与描述常使用$t:key字符串键(如'$t:interfaces.input.input'、'$t:interfaces.input.description'),由 Directus 前端的国际化机制统一解析,实际文案存储在 app/src/lang 下的各语言 YAML 文件中——这与文档中"借助 i18n 实现本地化"的目标一脉相承,只是落地形式从函数调用变成了声明式键。
name
name是接口面向用户的展示名称。它在字段配置向导、接口下拉选择列表中直接呈现给管理员。如 app/src/interfaces/boolean/index.ts 中name: '$t:interfaces.boolean.toggle',会在界面上显示为各语言环境对应的"Toggle/开关"文本。文档强调,借助i18n能力,名称可以做到本地化——在扁平配置下即为使用翻译键而非硬编码字符串。
icon
icon是界面中提及该接口时展示的图标,其最重要的出现场景是字段设置向导(field-setup wizard)中让用户挑选字段控件类型时的图标列表。图标使用 Directus 内置的 Material Design 图标名称字符串,例如文本输入框接口用text_fields,布尔开关接口用check_box。选择语义清晰的图标能显著提升数据建模时的辨识度。
component
component是构成接口输入的Vue 组件,它会在编辑表单中被实际渲染。以 app/src/interfaces/input/input.vue 为例,该组件通过<script setup>声明 props 接收字段的值与各类配置参数,并依赖 Directus 通用输入组件VInput与图标组件VIcon(位于 app/src/components)搭建 UI。接口组件与 Directus 前端之间的数据契约遵循统一的约定:通过valueprop 接收当前字段值,通过input事件把新值回传给上层(见源码中的defineEmits(['input']))。
options:面向字段配置的可视化参数面板
接口的options描述的是该接口自身可配置的"设置项字段",管理员在字段的高级配置面板中修改这些选项时,会实时以"表单套表单"的方式渲染出对应的编辑控件。依据 packages/types/src/extensions/interfaces.ts 的类型定义,options支持四种形态:
- 一组
DeepPartial<AppField>[]配置数组; { standard: AppField[]; advanced: AppField[] }分组对象(标准/高级两栏展示);- 一个接收
ctx的函数,根据上下文动态返回上述两种结构; null或独立的 VueComponentOptions(用于完全自定义的设置面板)。
input接口是"按字段类型动态返回选项"的典型范例:app/src/interfaces/input/index.ts 中的options是一个函数,它读取字段上下文{ field },若当前字段类型命中APP_NUMERIC_TYPES(来自 app/src/constants.ts),则返回min/max/step等数字专属选项(默认step: 1);否则返回placeholder、iconLeft、iconRight(标准分组)以及softLength(软长度限制,用于文字输入场景,默认占位 255)、font(sans-serif/monospace/serif 三选一,默认sans-serif)、trim、masked、clear、slug(布尔开关,默认均为false)等文本选项。每个选项本身又是一个完整的DeepPartial<Field>结构——拥有field(选项键名)、name、type、meta与schema.default_value,其中meta.interface指定渲染该选项时复用的接口id(如input、select-icon、select-dropdown、boolean、select-color)。
再看 app/src/interfaces/boolean/index.ts,它展示了一套选项与组件 props 的一一映射:iconOn/iconOff(开启/关闭图标,默认check_box与check_box_outline_blank)、colorOn/colorOff(高亮色)、label(展示文案),且推荐了配套展示组件recommendedDisplays: ['boolean']。
也就是说:声明 options 时给出的每个field键,都会在运行期作为 prop 传入你的component。组件内部只需声明同名 props 即可消费这些配置,例如 app/src/interfaces/input/input.vue 中定义了masked、trim、font、softLength、min、max、step等 props,并在computed中据此计算输入框的type(masked时为password,数字类型时为number)与剩余字符数提示。这套"配置即 props"的约定让接口开发者无需关心选项面板如何构建,只需专注在"拿到这些参数后如何渲染输入"这一件事上。
分组、类型匹配与可选进阶字段
除了文档重点讲解的id、register/name/icon/component,InterfaceConfig还定义了若干在当前仓库代码中大量使用的字段,理解它们能帮你写出与既有生态风格一致的接口:
| 属性 | 取值/类型 | 作用说明 |
|---|---|---|
description | 字符串/翻译键 | 接口的补充说明,展示于选择界面 |
types | Type[](如string、boolean、integer…) | 声明该接口可用于哪些字段类型,决定它在字段设置向导中的可选项范围(必填) |
localTypes | LocalType[] | 面向 alias、m2m、o2m 等本地(非原生 DB)类型的适用声明 |
group | standard|selection|relational|presentation|group|other | 接口所属分组,决定在向导中的归类展示 |
order | number | 在同一分组内的排序权重 |
relational | boolean | 标记为关系型接口(如 m2m/o2m 列表),影响加载与权限处理 |
recommendedDisplays | string[] | 为使用该接口的字段推荐默认的展示(Display)组件 id |
preview | string(如PreviewSVG) | 可选的缩略预览图/组件,用于在设置向导中直观呈现输入效果 |
system | boolean | 是否为系统内部接口(_system目录下的接口均为true风格实现) |
以input为例,其声明为types: ['string', 'uuid', 'bigInteger', 'integer', 'float', 'decimal', 'text']、group: 'standard',因此当你新建一个文本或整数字段时,向导才会把"Input"列为候选控件;boolean则声明types: ['boolean']、group: 'selection',只服务于布尔类型字段。这种类型白名单机制让字段建模界面保持克制且语义明确。
把接口放进 App 扩展生态
defineInterface与defineDisplay、defineLayout、defineModule、definePanel等函数一起被统一导出自@directus/extensions,它们构成 Directus 前端扩展声明的统一入口,实现文件均为 packages/extensions/src/shared/utils/define-extension.ts 中的同构身份函数。一条接口从声明到出现在编辑表单中的完整链路可概括为:
- 声明配置:调用
defineInterface传入InterfaceConfig(id/name/icon/component/types/group/options…); - 类型注册:配置对象经类型校验后原样返回,由扩展注册器收集进平台的接口注册表;
- 场景消费:字段设置向导按
types+group过滤出可用接口列表并展示icon与name;管理员保存字段后,编辑表单即渲染该接口的component,并将字段值与已配置的options作为 props 传入; - 交互回写:组件通过
input事件把编辑结果回传,完成一次数据编辑。
小结
本文以官方文档为纲,拆解了 Directus 接口组件的定义方式与四个核心元数据——用于内部定位的id、承载用户可见信息的register(含i18n本地化能力)、用于向导展示的name/icon,以及真正渲染输入的component,并结合当前仓库源码补齐了options动态声明、types/group匹配、recommendedDisplays与 props 数据契约等进阶细节。若你正打算为 Directus 编写第一个自定义接口,可先阅读 packages/types/src/extensions/interfaces.ts 掌握全部可配置字段,再对照 app/src/interfaces/input/index.ts 与 app/src/interfaces/boolean/index.ts 两份最小而完整的范例动手实践,即可快速产出符合平台规范、可本地化、可随字段类型自适应的输入控件。
【免费下载链接】directusThe flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.项目地址: https://gitcode.com/GitHub_Trending/di/directus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考