在现有项目中,我们通过扩展字段类型的方式支持自定义字段功能。这种机制虽然灵活,但存在一定的局限性:
某些场景下,我们并不需要新增一种字段类型,而是希望改变现有字段的展示形式,以适应不同的业务需求或用户体验优化。
以 URL 字段为例,目前它通常以纯文本方式展示。但我们可能需要以下多种展示方式:
这类需求并不需要新建字段类型,而应视为字段展示层的扩展能力。
通过 CollectionFieldInterfaceManager
提供的扩展机制,我们可以为现有字段类型添加多种展示组件选项,让用户能够根据具体需求选择合适的展示方式。
1interface CollectionFieldInterfaceComponentOption {
2 label: string; // 展示给用户的标签名称
3 value: string; // 组件的唯一标识符
4 useVisible?: () => boolean; // 控制该选项是否可见
5 useProps?: () => any; // 返回传递给组件的属性
6}
1class CollectionFieldInterfaceManager {
2 // 为指定字段类型添加展示组件选项
3 addFieldInterfaceComponentOption(
4 interfaceName: string,
5 componentOption: CollectionFieldInterfaceComponentOption
6 ): void;
7}
1// 定义
2interface CollectionFieldInterfaceComponentOption {
3 label: string;
4 value: string;
5 useVisible?: () => boolean;
6 useProps?: () => any;
7}
8
9class CollectionFieldInterfaceManager {
10 addFieldInterfaceComponentOption(
11 interfaceName: string,
12 componentOption:CollectionFieldInterfaceComponentOption
13 ): void
14}
15
16// 用法
17class MyPlugin extends Plugin {
18 async load() {
19 this.app.dataSourceManager.
20 collectionFieldInterfaceManager.
21 addFieldInterfaceComponentOption('url', {
22 label: 'Preview',
23 value: 'Input.Preview',
24 });
25 }
26}
1class UrlDisplayPlugin extends Plugin {
2 async load() {
3 const manager = this.app.dataSourceManager.collectionFieldInterfaceManager;
4
5 // 1. 可点击链接展示
6 manager.addFieldInterfaceComponentOption('url', {
7 label: '可点击链接',
8 value: 'UrlField.ClickableLink',
9 useProps: () => ({
10 target: '_blank',
11 rel: 'noopener noreferrer'
12 })
13 });
14
15 // 2. 链接预览展示
16 manager.addFieldInterfaceComponentOption('url', {
17 label: '链接预览',
18 value: 'UrlField.Preview',
19 useProps: () => ({
20 showTitle: true,
21 showThumbnail: true,
22 maxWidth: 300
23 })
24 });
25
26 // 3. 域名展示
27 manager.addFieldInterfaceComponentOption('url', {
28 label: '仅显示域名',
29 value: 'UrlField.DomainOnly',
30 useProps: () => ({
31 showProtocol: false,
32 showPath: false
33 })
34 });
35
36 // 4. 格式化展示
37 manager.addFieldInterfaceComponentOption('url', {
38 label: '格式化显示',
39 value: 'UrlField.Formatted',
40 useProps: () => ({
41 format: 'short',
42 maxLength: 50
43 })
44 });
45 }
46}
1class NumberDisplayPlugin extends Plugin {
2 async load() {
3 const manager = this.app.dataSourceManager.collectionFieldInterfaceManager;
4
5 // 1. 货币格式
6 manager.addFieldInterfaceComponentOption('number', {
7 label: '货币格式',
8 value: 'NumberField.Currency',
9 useProps: () => ({
10 currency: 'CNY',
11 precision: 2
12 })
13 });
14
15 // 2. 百分比格式
16 manager.addFieldInterfaceComponentOption('number', {
17 label: '百分比',
18 value: 'NumberField.Percentage',
19 useProps: () => ({
20 precision: 1,
21 suffix: '%'
22 })
23 });
24
25 // 3. 科学计数法
26 manager.addFieldInterfaceComponentOption('number', {
27 label: '科学计数法',
28 value: 'NumberField.Scientific',
29 useProps: () => ({
30 notation: 'scientific',
31 precision: 3
32 })
33 });
34 }
35}
1class DateDisplayPlugin extends Plugin {
2 async load() {
3 const manager = this.app.dataSourceManager.collectionFieldInterfaceManager;
4
5 // 1. 相对时间
6 manager.addFieldInterfaceComponentOption('datetime', {
7 label: '相对时间',
8 value: 'DateField.Relative',
9 useProps: () => ({
10 format: 'relative',
11 updateInterval: 60000 // 每分钟更新
12 })
13 });
14
15 // 2. 自定义格式
16 manager.addFieldInterfaceComponentOption('datetime', {
17 label: '自定义格式',
18 value: 'DateField.Custom',
19 useProps: () => ({
20 format: 'YYYY年MM月DD日 HH:mm:ss'
21 })
22 });
23
24 // 3. 时间范围
25 manager.addFieldInterfaceComponentOption('datetime', {
26 label: '时间范围',
27 value: 'DateField.Range',
28 useProps: () => ({
29 showRange: true,
30 rangeFormat: 'YYYY-MM-DD'
31 })
32 });
33 }
34}
1manager.addFieldInterfaceComponentOption('url', {
2 label: '高级预览',
3 value: 'UrlField.AdvancedPreview',
4 useVisible: () => {
5 // 只在特定条件下显示此选项
6 const currentUser = this.app.getCurrentUser();
7 return currentUser.hasPermission('advanced_preview');
8 },
9 useProps: () => ({
10 showMetadata: true,
11 showSecurityInfo: true
12 })
13});
1manager.addFieldInterfaceComponentOption('url', {
2 label: '开发模式预览',
3 value: 'UrlField.DevPreview',
4 useVisible: () => {
5 return process.env.NODE_ENV === 'development';
6 },
7 useProps: () => ({
8 showDebugInfo: true,
9 showPerformance: true
10 })
11});
1import { Plugin } from '@tachybase/client';
2
3export class FieldDisplayExtensionsPlugin extends Plugin {
4 async load() {
5 this.registerUrlFieldExtensions();
6 this.registerNumberFieldExtensions();
7 this.registerDateFieldExtensions();
8 }
9
10 private registerUrlFieldExtensions() {
11 const manager = this.app.dataSourceManager.collectionFieldInterfaceManager;
12
13 // 基础链接展示
14 manager.addFieldInterfaceComponentOption('url', {
15 label: '基础链接',
16 value: 'UrlField.Basic',
17 useProps: () => ({
18 target: '_blank',
19 className: 'url-link'
20 })
21 });
22
23 // 智能预览
24 manager.addFieldInterfaceComponentOption('url', {
25 label: '智能预览',
26 value: 'UrlField.SmartPreview',
27 useProps: () => ({
28 fetchMetadata: true,
29 showFavicon: true,
30 showDescription: true,
31 maxDescriptionLength: 100
32 })
33 });
34
35 // 安全链接
36 manager.addFieldInterfaceComponentOption('url', {
37 label: '安全链接',
38 value: 'UrlField.Secure',
39 useProps: () => ({
40 showSecurityBadge: true,
41 validateSSL: true,
42 showDomainInfo: true
43 })
44 });
45 }
46
47 private registerNumberFieldExtensions() {
48 const manager = this.app.dataSourceManager.collectionFieldInterfaceManager;
49
50 // 千分位分隔
51 manager.addFieldInterfaceComponentOption('number', {
52 label: '千分位分隔',
53 value: 'NumberField.Thousands',
54 useProps: () => ({
55 separator: ',',
56 precision: 0
57 })
58 });
59
60 // 文件大小
61 manager.addFieldInterfaceComponentOption('number', {
62 label: '文件大小',
63 value: 'NumberField.FileSize',
64 useProps: () => ({
65 format: 'fileSize',
66 precision: 2
67 })
68 });
69 }
70
71 private registerDateFieldExtensions() {
72 const manager = this.app.dataSourceManager.collectionFieldInterfaceManager;
73
74 // 倒计时
75 manager.addFieldInterfaceComponentOption('datetime', {
76 label: '倒计时',
77 value: 'DateField.Countdown',
78 useProps: () => ({
79 format: 'countdown',
80 showDays: true,
81 showHours: true,
82 showMinutes: true
83 })
84 });
85 }
86}
1// 在应用中注册插件
2import { FieldDisplayExtensionsPlugin } from './plugins/FieldDisplayExtensionsPlugin';
3
4const app = new Application({
5 plugins: [
6 FieldDisplayExtensionsPlugin,
7 // 其他插件...
8 ]
9});
FieldType.ComponentName
格式useProps
中避免复杂的计算useVisible
控制选项显示通过字段展示扩展机制,我们可以在不改变字段类型的情况下,为现有字段提供丰富的展示形式。这种设计既保持了系统的灵活性,又避免了不必要的复杂性,是提升用户体验的有效方式。