@ticatec/uniface-element 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +320 -1
- package/README_CN.md +392 -0
- package/dist/accordion/Accordion.svelte +1 -1
- package/dist/action-bar/ActionBar.svelte +7 -1
- package/dist/attachment-files/FileRender.svelte +1 -1
- package/dist/attachment-files/FileUploadBar.svelte +7 -6
- package/dist/attachment-files/FileUploadPanel.svelte +2 -2
- package/dist/base-calendar/DateContext.js +5 -4
- package/dist/base-calendar/YearPickupPanel.svelte +4 -4
- package/dist/card/Card.svelte +1 -1
- package/dist/card/Card.svelte.d.ts +1 -1
- package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
- package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
- package/dist/cascade-options-select/CascadePanel.svelte +1 -1
- package/dist/checkbox/CheckBox.svelte +1 -1
- package/dist/color-picker/ColorPicker.svelte +9 -9
- package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
- package/dist/color-picker/ColorPickerPanel.svelte +11 -15
- package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
- package/dist/common/CommonPicker.svelte +2 -2
- package/dist/common/CommonPicker.svelte.d.ts +1 -1
- package/dist/common/MouseClickHandler.d.ts +1 -1
- package/dist/common/Popover.svelte +28 -6
- package/dist/common/Popover.svelte.d.ts +9 -3
- package/dist/common/uniface-utils.js +6 -4
- package/dist/common-editor/CommonEditor.svelte +1 -1
- package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
- package/dist/common-editor/NumberInput.svelte +1 -1
- package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
- package/dist/concise-data-table/ConciseListTable.svelte +7 -2
- package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
- package/dist/concise-data-table/DataRow.svelte +1 -1
- package/dist/concise-data-table/TableOptions.d.ts +1 -1
- package/dist/data-table/DataTable.svelte +1 -1
- package/dist/data-table/parts/ActionsPanel.svelte +4 -3
- package/dist/data-table/parts/ActionsRow.svelte +3 -3
- package/dist/data-table/parts/ContentPanel.svelte +3 -2
- package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
- package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
- package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
- package/dist/data-table/parts/FixedRow.svelte +2 -1
- package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
- package/dist/data-table/parts/HrefCell.svelte +23 -2
- package/dist/data-table/parts/PopupMenu.svelte +25 -2
- package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
- package/dist/date-picker/DatePicker.svelte +0 -1
- package/dist/date-picker/DateTimePicker.svelte +3 -3
- package/dist/date-picker/ScrollBar.svelte +4 -7
- package/dist/date-range/DateRangeEditor.svelte +1 -1
- package/dist/dialog/CommonDialog.svelte +8 -5
- package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
- package/dist/dialog/Dialog.svelte +37 -12
- package/dist/dialog/Dialog.svelte.d.ts +4 -3
- package/dist/dialog/DialogBoard.svelte +11 -8
- package/dist/dialog/DialogWrapper.svelte +10 -0
- package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
- package/dist/dialog/Dialogs.js +1 -1
- package/dist/dialog/ModalResult.d.ts +5 -0
- package/dist/dialog/ModalResult.js +5 -0
- package/dist/drawer/Drawer.svelte +1 -1
- package/dist/form-field/FormField.svelte +2 -1
- package/dist/form-field/FormField.svelte.d.ts +1 -0
- package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
- package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
- package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
- package/dist/form-panel/grid-form/GridField.svelte +1 -1
- package/dist/i18nRes/i18nRes.d.ts +2 -0
- package/dist/i18nRes/i18nRes.js +44 -0
- package/dist/i18nRes/index.d.ts +2 -0
- package/dist/i18nRes/index.js +2 -0
- package/dist/image-files/ImageFilesField.svelte +1 -1
- package/dist/indicator/IndicatorBoard.svelte +1 -1
- package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
- package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
- package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
- package/dist/layout/flex/FlexBlock.svelte +1 -1
- package/dist/lookup-editor/LookupEditor.svelte +1 -1
- package/dist/memo-editor/MemoEditor.svelte +2 -2
- package/dist/message-box/IMessageBox.d.ts +2 -4
- package/dist/message-box/IMessageBox.js +4 -6
- package/dist/message-box/MessageBoxBoard.svelte +1 -3
- package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
- package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
- package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
- package/dist/property-editor/PropertyEditor.svelte +3 -3
- package/dist/text-editor/PasswordEditor.svelte +1 -1
- package/dist/transfer/Transfer.svelte +17 -12
- package/dist/transfer/Transfer.svelte.d.ts +0 -1
- package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
- package/docs/buttons/cn/ActionBar.md +459 -0
- package/docs/buttons/cn/Button.md +228 -0
- package/docs/buttons/cn/IconButton.md +294 -0
- package/docs/buttons/cn/README.md +600 -0
- package/docs/buttons/cn/TextButton.md +163 -0
- package/docs/buttons/en/ActionBar.md +459 -0
- package/docs/buttons/en/Button.md +228 -0
- package/docs/buttons/en/IconButton.md +294 -0
- package/docs/buttons/en/README.md +600 -0
- package/docs/buttons/en/TextButton.md +163 -0
- package/docs/containers/cn/accordion.md +622 -0
- package/docs/containers/cn/box.md +445 -0
- package/docs/containers/cn/card.md +404 -0
- package/docs/containers/cn/page.md +576 -0
- package/docs/containers/cn/tabs.md +686 -0
- package/docs/containers/en/accordion.md +622 -0
- package/docs/containers/en/box.md +445 -0
- package/docs/containers/en/card.md +404 -0
- package/docs/containers/en/page.md +576 -0
- package/docs/containers/en/tabs.md +686 -0
- package/docs/data-display/cn/concise-data-table.md +731 -0
- package/docs/data-display/cn/listbox.md +786 -0
- package/docs/data-display/cn/treeview.md +863 -0
- package/docs/data-display/en/concise-data-table.md +732 -0
- package/docs/data-display/en/listbox.md +786 -0
- package/docs/data-display/en/treeview.md +863 -0
- package/docs/data-table/cn/README.md +596 -0
- package/docs/data-table/en/README.md +596 -0
- package/docs/dialog/cn/README.md +767 -0
- package/docs/dialog/en/README.md +767 -0
- package/docs/form/cn/README.md +847 -0
- package/docs/form/en/README.md +847 -0
- package/docs/form-components/cn/README.md +495 -0
- package/docs/form-components/cn/attachmentfilesfield.md +757 -0
- package/docs/form-components/cn/cascade-options-select.md +374 -0
- package/docs/form-components/cn/checkbox.md +58 -0
- package/docs/form-components/cn/date-picker.md +138 -0
- package/docs/form-components/cn/datetime-picker.md +228 -0
- package/docs/form-components/cn/group-checkbox.md +405 -0
- package/docs/form-components/cn/group-radiobox.md +525 -0
- package/docs/form-components/cn/imagefilesfield.md +651 -0
- package/docs/form-components/cn/input-options-select.md +250 -0
- package/docs/form-components/cn/lookup-editor.md +406 -0
- package/docs/form-components/cn/memoeditor.md +409 -0
- package/docs/form-components/cn/number-editor.md +261 -0
- package/docs/form-components/cn/options-multi-select.md +177 -0
- package/docs/form-components/cn/options-select.md +83 -0
- package/docs/form-components/cn/passwordeditor.md +538 -0
- package/docs/form-components/cn/prompts-text-editor.md +241 -0
- package/docs/form-components/cn/radiobutton.md +84 -0
- package/docs/form-components/cn/switch.md +178 -0
- package/docs/form-components/cn/text-editor.md +142 -0
- package/docs/form-components/cn/time-editor.md +159 -0
- package/docs/form-components/cn/unit-number-editor.md +164 -0
- package/docs/form-components/en/README.md +463 -0
- package/docs/form-components/en/attachmentfilesfield.md +757 -0
- package/docs/form-components/en/cascade-options-select.md +358 -0
- package/docs/form-components/en/checkbox.md +59 -0
- package/docs/form-components/en/date-picker.md +138 -0
- package/docs/form-components/en/datetime-picker.md +228 -0
- package/docs/form-components/en/group-checkbox.md +395 -0
- package/docs/form-components/en/group-radiobox.md +498 -0
- package/docs/form-components/en/imagefilesfield.md +651 -0
- package/docs/form-components/en/input-options-select.md +239 -0
- package/docs/form-components/en/lookup-editor.md +389 -0
- package/docs/form-components/en/memoeditor.md +409 -0
- package/docs/form-components/en/number-editor.md +249 -0
- package/docs/form-components/en/options-multi-select.md +177 -0
- package/docs/form-components/en/options-select.md +83 -0
- package/docs/form-components/en/passwordeditor.md +538 -0
- package/docs/form-components/en/prompts-text-editor.md +241 -0
- package/docs/form-components/en/radiobutton.md +84 -0
- package/docs/form-components/en/switch.md +180 -0
- package/docs/form-components/en/text-editor.md +142 -0
- package/docs/form-components/en/time-editor.md +159 -0
- package/docs/form-components/en/unit-number-editor.md +164 -0
- package/docs/form-layout/cn/criteria-field.md +652 -0
- package/docs/form-layout/cn/flex-form.md +454 -0
- package/docs/form-layout/cn/flex-row-form.md +542 -0
- package/docs/form-layout/cn/form-field.md +923 -0
- package/docs/form-layout/cn/grid-form.md +676 -0
- package/docs/form-layout/en/criteria-field.md +652 -0
- package/docs/form-layout/en/flex-form.md +454 -0
- package/docs/form-layout/en/flex-row-form.md +542 -0
- package/docs/form-layout/en/form-field.md +923 -0
- package/docs/form-layout/en/grid-form.md +676 -0
- package/docs/global/cn/README.md +534 -0
- package/docs/global/en/README.md +534 -0
- package/docs/layout/cn/classiclayout.md +460 -0
- package/docs/layout/cn/headerlayout.md +524 -0
- package/docs/layout/cn/sidebarlayout.md +263 -0
- package/docs/layout/en/classiclayout.md +951 -0
- package/docs/layout/en/headerlayout.md +524 -0
- package/docs/layout/en/sidebarlayout.md +262 -0
- package/docs/misc/cn/README.md +1217 -0
- package/docs/misc/en/README.md +1217 -0
- package/docs/navigation/cn/breadcrumb.md +291 -0
- package/docs/navigation/cn/navigator.md +322 -0
- package/docs/navigation/cn/navigatormenu.md +512 -0
- package/docs/navigation/cn/progressbar.md +199 -0
- package/docs/navigation/cn/progressstepbar.md +299 -0
- package/docs/navigation/en/breadcrumb.md +291 -0
- package/docs/navigation/en/navigator.md +322 -0
- package/docs/navigation/en/navigatormenu.md +512 -0
- package/docs/navigation/en/progressbar.md +199 -0
- package/docs/navigation/en/progressstepbar.md +299 -0
- package/docs/search-filters/cn/daterange.md +1156 -0
- package/docs/search-filters/cn/numberrange.md +688 -0
- package/docs/search-filters/cn/searchbox.md +1582 -0
- package/docs/search-filters/en/daterange.md +1156 -0
- package/docs/search-filters/en/numberrange.md +688 -0
- package/docs/search-filters/en/searchbox.md +1582 -0
- package/package.json +53 -13
- package/dist/common-editor/DateInput.svelte +0 -27
- package/dist/i18n_resources/index.d.ts +0 -3
- package/dist/i18n_resources/index.js +0 -3
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.js +0 -0
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
# Tabs 标签页组件
|
|
2
|
+
|
|
3
|
+
一个灵活且功能丰富的标签页界面组件,允许将内容组织为多个可切换的面板,支持滚动、关闭和自定义标签页渲染。
|
|
4
|
+
|
|
5
|
+
## 概述
|
|
6
|
+
|
|
7
|
+
Tabs 组件提供了一种直观的方式来将相关内容组织到单独的、可导航的面板中。它包含高级功能,如多个标签页的水平滚动、可关闭标签页、重新加载功能和自定义标签页渲染。非常适合用于仪表板、设置面板、多步骤表单和内容组织。
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
13
|
+
import type { TabActionHandler, TabCloseHandler, TabRender } from '@ticatec/uniface-element/Tabs';
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 基本用法
|
|
17
|
+
|
|
18
|
+
```svelte
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
21
|
+
|
|
22
|
+
let tabData = [
|
|
23
|
+
{ id: 1, text: '仪表板', content: 'dashboard' },
|
|
24
|
+
{ id: 2, text: '用户', content: 'users' },
|
|
25
|
+
{ id: 3, text: '设置', content: 'settings' }
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
let activeTab = tabData[0];
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<Tabs tabs={tabData} bind:activeTab>
|
|
32
|
+
<div class="tab-content">
|
|
33
|
+
{#if activeTab.content === 'dashboard'}
|
|
34
|
+
<div class="dashboard-panel">
|
|
35
|
+
<h3>仪表板内容</h3>
|
|
36
|
+
<p>欢迎来到您的仪表板...</p>
|
|
37
|
+
</div>
|
|
38
|
+
{:else if activeTab.content === 'users'}
|
|
39
|
+
<div class="users-panel">
|
|
40
|
+
<h3>用户管理</h3>
|
|
41
|
+
<p>在这里管理您的用户...</p>
|
|
42
|
+
</div>
|
|
43
|
+
{:else if activeTab.content === 'settings'}
|
|
44
|
+
<div class="settings-panel">
|
|
45
|
+
<h3>应用程序设置</h3>
|
|
46
|
+
<p>配置您的应用程序...</p>
|
|
47
|
+
</div>
|
|
48
|
+
{/if}
|
|
49
|
+
</div>
|
|
50
|
+
</Tabs>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 属性
|
|
54
|
+
|
|
55
|
+
| 属性 | 类型 | 默认值 | 描述 |
|
|
56
|
+
|------|------|--------|------|
|
|
57
|
+
| `class` | `string` | `""` | 额外的 CSS 类名 |
|
|
58
|
+
| `simple` | `boolean` | `false` | 使用简化的标签页样式 |
|
|
59
|
+
| `textField` | `string` | `'text'` | 用于标签页文本的属性名称 |
|
|
60
|
+
| `style` | `string` | `''` | 标签页容器的自定义 CSS 样式 |
|
|
61
|
+
| `tabs` | `Array<any>` | `[]` | 标签页对象数组 |
|
|
62
|
+
| `scrollStep` | `number` | `100` | 使用滚动按钮时滚动的像素数 |
|
|
63
|
+
| `closable` | `boolean \| TabActionHandler` | `false` | 启用标签页关闭或自定义关闭逻辑 |
|
|
64
|
+
| `activeTab` | `any` | `null` | 当前活动的标签页对象 |
|
|
65
|
+
| `tabRender` | `TabRender` | `null` | 自定义标签页渲染组件 |
|
|
66
|
+
| `reloadHandler` | `TabActionHandler` | `null` | 标签页重新加载操作的处理程序 |
|
|
67
|
+
| `closeHandler` | `TabCloseHandler` | `null` | 标签页关闭操作的处理程序 |
|
|
68
|
+
|
|
69
|
+
## 类型定义
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
export type TabActionHandler = (tab: any) => void;
|
|
73
|
+
export type TabCloseHandler = (tab: any) => Promise<boolean>;
|
|
74
|
+
export type TabRender = (tab: any) => any;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 使用示例
|
|
78
|
+
|
|
79
|
+
### 基础标签页
|
|
80
|
+
|
|
81
|
+
```svelte
|
|
82
|
+
<script lang="ts">
|
|
83
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
84
|
+
|
|
85
|
+
let navigationTabs = [
|
|
86
|
+
{ id: 'overview', text: '概览' },
|
|
87
|
+
{ id: 'analytics', text: '分析' },
|
|
88
|
+
{ id: 'reports', text: '报告' },
|
|
89
|
+
{ id: 'settings', text: '设置' }
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
let currentTab = navigationTabs[0];
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<Tabs tabs={navigationTabs} bind:activeTab={currentTab}>
|
|
96
|
+
<div class="content-area">
|
|
97
|
+
{#if currentTab.id === 'overview'}
|
|
98
|
+
<h2>系统概览</h2>
|
|
99
|
+
<p>一般系统信息和状态。</p>
|
|
100
|
+
{:else if currentTab.id === 'analytics'}
|
|
101
|
+
<h2>分析仪表板</h2>
|
|
102
|
+
<p>查看详细的分析和指标。</p>
|
|
103
|
+
{:else if currentTab.id === 'reports'}
|
|
104
|
+
<h2>报告</h2>
|
|
105
|
+
<p>生成和查看系统报告。</p>
|
|
106
|
+
{:else if currentTab.id === 'settings'}
|
|
107
|
+
<h2>配置</h2>
|
|
108
|
+
<p>管理系统设置和首选项。</p>
|
|
109
|
+
{/if}
|
|
110
|
+
</div>
|
|
111
|
+
</Tabs>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 可关闭标签页
|
|
115
|
+
|
|
116
|
+
```svelte
|
|
117
|
+
<script lang="ts">
|
|
118
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
119
|
+
import type { TabCloseHandler } from '@ticatec/uniface-element/Tabs';
|
|
120
|
+
|
|
121
|
+
let documentTabs = [
|
|
122
|
+
{ id: 1, text: '文档 1', modified: false },
|
|
123
|
+
{ id: 2, text: '文档 2', modified: true },
|
|
124
|
+
{ id: 3, text: '文档 3', modified: false }
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
let activeDocument = documentTabs[0];
|
|
128
|
+
|
|
129
|
+
const handleTabClose: TabCloseHandler = async (tab) => {
|
|
130
|
+
if (tab.modified) {
|
|
131
|
+
const shouldClose = confirm(`"${tab.text}" 有未保存的更改。仍要关闭吗?`);
|
|
132
|
+
return shouldClose;
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
};
|
|
136
|
+
</script>
|
|
137
|
+
|
|
138
|
+
<Tabs
|
|
139
|
+
tabs={documentTabs}
|
|
140
|
+
bind:activeTab={activeDocument}
|
|
141
|
+
closable={true}
|
|
142
|
+
closeHandler={handleTabClose}
|
|
143
|
+
>
|
|
144
|
+
<div class="document-editor">
|
|
145
|
+
<h3>正在编辑: {activeDocument.text}</h3>
|
|
146
|
+
<textarea placeholder="文档内容..." rows="10" cols="50"></textarea>
|
|
147
|
+
{#if activeDocument.modified}
|
|
148
|
+
<p class="unsaved-indicator">• 未保存的更改</p>
|
|
149
|
+
{/if}
|
|
150
|
+
</div>
|
|
151
|
+
</Tabs>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 带重新加载功能的标签页
|
|
155
|
+
|
|
156
|
+
```svelte
|
|
157
|
+
<script lang="ts">
|
|
158
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
159
|
+
import type { TabActionHandler } from '@ticatec/uniface-element/Tabs';
|
|
160
|
+
|
|
161
|
+
let dataTabs = [
|
|
162
|
+
{ id: 'users', text: '用户', lastRefresh: new Date() },
|
|
163
|
+
{ id: 'orders', text: '订单', lastRefresh: new Date() },
|
|
164
|
+
{ id: 'products', text: '产品', lastRefresh: new Date() }
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
let activeDataTab = dataTabs[0];
|
|
168
|
+
|
|
169
|
+
const handleTabReload: TabActionHandler = (tab) => {
|
|
170
|
+
console.log(`正在重新加载 ${tab.text} 数据...`);
|
|
171
|
+
tab.lastRefresh = new Date();
|
|
172
|
+
// 在这里触发数据刷新逻辑
|
|
173
|
+
refreshTabData(tab.id);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
function refreshTabData(tabId: string) {
|
|
177
|
+
// 模拟数据刷新
|
|
178
|
+
console.log(`正在刷新标签页数据: ${tabId}`);
|
|
179
|
+
}
|
|
180
|
+
</script>
|
|
181
|
+
|
|
182
|
+
<Tabs
|
|
183
|
+
tabs={dataTabs}
|
|
184
|
+
bind:activeTab={activeDataTab}
|
|
185
|
+
reloadHandler={handleTabReload}
|
|
186
|
+
>
|
|
187
|
+
<div class="data-panel">
|
|
188
|
+
<div class="panel-header">
|
|
189
|
+
<h3>{activeDataTab.text} 数据</h3>
|
|
190
|
+
<small>最后刷新: {activeDataTab.lastRefresh.toLocaleTimeString()}</small>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div class="data-content">
|
|
194
|
+
{#if activeDataTab.id === 'users'}
|
|
195
|
+
<p>用户管理界面...</p>
|
|
196
|
+
{:else if activeDataTab.id === 'orders'}
|
|
197
|
+
<p>订单跟踪和管理...</p>
|
|
198
|
+
{:else if activeDataTab.id === 'products'}
|
|
199
|
+
<p>产品目录管理...</p>
|
|
200
|
+
{/if}
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
</Tabs>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 自定义标签页字段
|
|
207
|
+
|
|
208
|
+
```svelte
|
|
209
|
+
<script lang="ts">
|
|
210
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
211
|
+
|
|
212
|
+
// 使用自定义字段名称作为标签页标签
|
|
213
|
+
let projectTabs = [
|
|
214
|
+
{ projectId: 'proj-1', name: '网站重新设计', status: 'active' },
|
|
215
|
+
{ projectId: 'proj-2', name: '移动应用', status: 'completed' },
|
|
216
|
+
{ projectId: 'proj-3', name: 'API 集成', status: 'pending' }
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
let selectedProject = projectTabs[0];
|
|
220
|
+
</script>
|
|
221
|
+
|
|
222
|
+
<Tabs
|
|
223
|
+
tabs={projectTabs}
|
|
224
|
+
bind:activeTab={selectedProject}
|
|
225
|
+
textField="name"
|
|
226
|
+
>
|
|
227
|
+
<div class="project-details">
|
|
228
|
+
<h2>{selectedProject.name}</h2>
|
|
229
|
+
<p>项目 ID: {selectedProject.projectId}</p>
|
|
230
|
+
<p>状态: <span class="status-{selectedProject.status}">{selectedProject.status}</span></p>
|
|
231
|
+
</div>
|
|
232
|
+
</Tabs>
|
|
233
|
+
|
|
234
|
+
<style>
|
|
235
|
+
.status-active { color: #28a745; }
|
|
236
|
+
.status-completed { color: #6c757d; }
|
|
237
|
+
.status-pending { color: #ffc107; }
|
|
238
|
+
</style>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 带多个项目的可滚动标签页
|
|
242
|
+
|
|
243
|
+
```svelte
|
|
244
|
+
<script lang="ts">
|
|
245
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
246
|
+
|
|
247
|
+
// 生成多个标签页以演示滚动功能
|
|
248
|
+
let manyTabs = Array.from({ length: 20 }, (_, i) => ({
|
|
249
|
+
id: i + 1,
|
|
250
|
+
text: `标签页 ${i + 1}`,
|
|
251
|
+
content: `标签页 ${i + 1} 的内容`
|
|
252
|
+
}));
|
|
253
|
+
|
|
254
|
+
let activeManyTab = manyTabs[0];
|
|
255
|
+
</script>
|
|
256
|
+
|
|
257
|
+
<div style="max-width: 600px; margin: 20px 0;">
|
|
258
|
+
<Tabs
|
|
259
|
+
tabs={manyTabs}
|
|
260
|
+
bind:activeTab={activeManyTab}
|
|
261
|
+
scrollStep={150}
|
|
262
|
+
style="border: 1px solid #dee2e6; border-radius: 8px;"
|
|
263
|
+
>
|
|
264
|
+
<div class="scrollable-content">
|
|
265
|
+
<h3>{activeManyTab.text}</h3>
|
|
266
|
+
<p>{activeManyTab.content}</p>
|
|
267
|
+
<p>这演示了当有很多标签页时的水平滚动。</p>
|
|
268
|
+
</div>
|
|
269
|
+
</Tabs>
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
<style>
|
|
273
|
+
.scrollable-content {
|
|
274
|
+
padding: 20px;
|
|
275
|
+
min-height: 200px;
|
|
276
|
+
}
|
|
277
|
+
</style>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 自定义标签页渲染
|
|
281
|
+
|
|
282
|
+
```svelte
|
|
283
|
+
<script lang="ts">
|
|
284
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
285
|
+
import type { TabRender } from '@ticatec/uniface-element/Tabs';
|
|
286
|
+
import CustomTabRenderer from './CustomTabRenderer.svelte';
|
|
287
|
+
|
|
288
|
+
let notificationTabs = [
|
|
289
|
+
{ id: 'inbox', text: '收件箱', count: 5, icon: 'inbox' },
|
|
290
|
+
{ id: 'sent', text: '已发送', count: 0, icon: 'send' },
|
|
291
|
+
{ id: 'drafts', text: '草稿', count: 2, icon: 'draft' },
|
|
292
|
+
{ id: 'trash', text: '回收站', count: 1, icon: 'delete' }
|
|
293
|
+
];
|
|
294
|
+
|
|
295
|
+
let activeNotificationTab = notificationTabs[0];
|
|
296
|
+
|
|
297
|
+
// 自定义标签页渲染器组件
|
|
298
|
+
const customTabRenderer: TabRender = CustomTabRenderer;
|
|
299
|
+
</script>
|
|
300
|
+
|
|
301
|
+
<Tabs
|
|
302
|
+
tabs={notificationTabs}
|
|
303
|
+
bind:activeTab={activeNotificationTab}
|
|
304
|
+
tabRender={customTabRenderer}
|
|
305
|
+
>
|
|
306
|
+
<div class="notification-panel">
|
|
307
|
+
<h3>{activeNotificationTab.text}</h3>
|
|
308
|
+
<p>项目数: {activeNotificationTab.count}</p>
|
|
309
|
+
|
|
310
|
+
{#if activeNotificationTab.id === 'inbox'}
|
|
311
|
+
<div class="inbox-content">
|
|
312
|
+
<p>您有 {activeNotificationTab.count} 条新消息。</p>
|
|
313
|
+
</div>
|
|
314
|
+
{:else if activeNotificationTab.id === 'drafts'}
|
|
315
|
+
<div class="drafts-content">
|
|
316
|
+
<p>您有 {activeNotificationTab.count} 条草稿消息。</p>
|
|
317
|
+
</div>
|
|
318
|
+
{:else}
|
|
319
|
+
<div class="empty-content">
|
|
320
|
+
<p>{activeNotificationTab.text} 中没有项目。</p>
|
|
321
|
+
</div>
|
|
322
|
+
{/if}
|
|
323
|
+
</div>
|
|
324
|
+
</Tabs>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
CustomTabRenderer.svelte:
|
|
328
|
+
```svelte
|
|
329
|
+
<script lang="ts">
|
|
330
|
+
export let tab: any;
|
|
331
|
+
export let closable: boolean = false;
|
|
332
|
+
export let closeTab: (() => void) | null = null;
|
|
333
|
+
export let reloadTab: (() => void) | null = null;
|
|
334
|
+
</script>
|
|
335
|
+
|
|
336
|
+
<div class="custom-tab">
|
|
337
|
+
<i class="icon-{tab.icon}"></i>
|
|
338
|
+
<span class="tab-text">{tab.text}</span>
|
|
339
|
+
{#if tab.count > 0}
|
|
340
|
+
<span class="badge">{tab.count}</span>
|
|
341
|
+
{/if}
|
|
342
|
+
|
|
343
|
+
{#if reloadTab}
|
|
344
|
+
<button class="tab-action reload" on:click={reloadTab} aria-label="重新加载">
|
|
345
|
+
<i class="icon-refresh"></i>
|
|
346
|
+
</button>
|
|
347
|
+
{/if}
|
|
348
|
+
|
|
349
|
+
{#if closable && closeTab}
|
|
350
|
+
<button class="tab-action close" on:click={closeTab} aria-label="关闭">
|
|
351
|
+
<i class="icon-close"></i>
|
|
352
|
+
</button>
|
|
353
|
+
{/if}
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<style>
|
|
357
|
+
.custom-tab {
|
|
358
|
+
display: flex;
|
|
359
|
+
align-items: center;
|
|
360
|
+
gap: 6px;
|
|
361
|
+
padding: 8px 12px;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.badge {
|
|
365
|
+
background: #dc3545;
|
|
366
|
+
color: white;
|
|
367
|
+
font-size: 0.75rem;
|
|
368
|
+
padding: 2px 6px;
|
|
369
|
+
border-radius: 10px;
|
|
370
|
+
min-width: 18px;
|
|
371
|
+
text-align: center;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.tab-action {
|
|
375
|
+
background: none;
|
|
376
|
+
border: none;
|
|
377
|
+
cursor: pointer;
|
|
378
|
+
padding: 2px;
|
|
379
|
+
opacity: 0.6;
|
|
380
|
+
transition: opacity 0.2s;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.tab-action:hover {
|
|
384
|
+
opacity: 1;
|
|
385
|
+
}
|
|
386
|
+
</style>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### 带动态内容的高级标签页
|
|
390
|
+
|
|
391
|
+
```svelte
|
|
392
|
+
<script lang="ts">
|
|
393
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
394
|
+
import type { TabActionHandler, TabCloseHandler } from '@ticatec/uniface-element/Tabs';
|
|
395
|
+
|
|
396
|
+
let workspaceTabs = [
|
|
397
|
+
{ id: 'workspace-1', text: '主工作区', type: 'workspace', canClose: false },
|
|
398
|
+
{ id: 'file-1', text: 'app.js', type: 'file', modified: false, canClose: true },
|
|
399
|
+
{ id: 'file-2', text: 'styles.css', type: 'file', modified: true, canClose: true }
|
|
400
|
+
];
|
|
401
|
+
|
|
402
|
+
let activeWorkspaceTab = workspaceTabs[0];
|
|
403
|
+
|
|
404
|
+
const isClosable: TabActionHandler = (tab) => {
|
|
405
|
+
return tab.canClose === true;
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
const handleClose: TabCloseHandler = async (tab) => {
|
|
409
|
+
if (tab.type === 'file' && tab.modified) {
|
|
410
|
+
const save = confirm(`保存对 ${tab.text} 的更改?`);
|
|
411
|
+
if (save) {
|
|
412
|
+
// 模拟保存操作
|
|
413
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
414
|
+
tab.modified = false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return true;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const handleReload: TabActionHandler = (tab) => {
|
|
421
|
+
if (tab.type === 'file') {
|
|
422
|
+
console.log(`重新加载文件: ${tab.text}`);
|
|
423
|
+
tab.modified = false;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
function addNewFile() {
|
|
428
|
+
const fileId = `file-${Date.now()}`;
|
|
429
|
+
const newFile = {
|
|
430
|
+
id: fileId,
|
|
431
|
+
text: '未命名.txt',
|
|
432
|
+
type: 'file',
|
|
433
|
+
modified: false,
|
|
434
|
+
canClose: true
|
|
435
|
+
};
|
|
436
|
+
workspaceTabs = [...workspaceTabs, newFile];
|
|
437
|
+
activeWorkspaceTab = newFile;
|
|
438
|
+
}
|
|
439
|
+
</script>
|
|
440
|
+
|
|
441
|
+
<div class="ide-interface">
|
|
442
|
+
<div class="toolbar">
|
|
443
|
+
<button on:click={addNewFile} class="btn-new-file">
|
|
444
|
+
+ 新建文件
|
|
445
|
+
</button>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
<Tabs
|
|
449
|
+
tabs={workspaceTabs}
|
|
450
|
+
bind:activeTab={activeWorkspaceTab}
|
|
451
|
+
closable={isClosable}
|
|
452
|
+
closeHandler={handleClose}
|
|
453
|
+
reloadHandler={handleReload}
|
|
454
|
+
class="ide-tabs"
|
|
455
|
+
>
|
|
456
|
+
<div class="editor-area">
|
|
457
|
+
{#if activeWorkspaceTab.type === 'workspace'}
|
|
458
|
+
<div class="workspace-content">
|
|
459
|
+
<h3>欢迎来到工作区</h3>
|
|
460
|
+
<p>打开的文件将显示为上方的标签页。</p>
|
|
461
|
+
</div>
|
|
462
|
+
{:else if activeWorkspaceTab.type === 'file'}
|
|
463
|
+
<div class="file-editor">
|
|
464
|
+
<div class="file-header">
|
|
465
|
+
<h4>{activeWorkspaceTab.text}</h4>
|
|
466
|
+
{#if activeWorkspaceTab.modified}
|
|
467
|
+
<span class="modified-indicator">●</span>
|
|
468
|
+
{/if}
|
|
469
|
+
</div>
|
|
470
|
+
<textarea
|
|
471
|
+
class="code-editor"
|
|
472
|
+
placeholder="在这里输入您的代码..."
|
|
473
|
+
on:input={() => activeWorkspaceTab.modified = true}
|
|
474
|
+
></textarea>
|
|
475
|
+
</div>
|
|
476
|
+
{/if}
|
|
477
|
+
</div>
|
|
478
|
+
</Tabs>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<style>
|
|
482
|
+
.ide-interface {
|
|
483
|
+
border: 1px solid #ccc;
|
|
484
|
+
border-radius: 8px;
|
|
485
|
+
overflow: hidden;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.toolbar {
|
|
489
|
+
background: #f8f9fa;
|
|
490
|
+
padding: 8px 16px;
|
|
491
|
+
border-bottom: 1px solid #dee2e6;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.btn-new-file {
|
|
495
|
+
padding: 6px 12px;
|
|
496
|
+
background: #007bff;
|
|
497
|
+
color: white;
|
|
498
|
+
border: none;
|
|
499
|
+
border-radius: 4px;
|
|
500
|
+
cursor: pointer;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.editor-area {
|
|
504
|
+
min-height: 300px;
|
|
505
|
+
padding: 16px;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.file-header {
|
|
509
|
+
display: flex;
|
|
510
|
+
align-items: center;
|
|
511
|
+
gap: 8px;
|
|
512
|
+
margin-bottom: 12px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.file-header h4 {
|
|
516
|
+
margin: 0;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.modified-indicator {
|
|
520
|
+
color: #ffc107;
|
|
521
|
+
font-size: 1.5rem;
|
|
522
|
+
line-height: 1;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.code-editor {
|
|
526
|
+
width: 100%;
|
|
527
|
+
height: 200px;
|
|
528
|
+
font-family: 'Courier New', monospace;
|
|
529
|
+
padding: 12px;
|
|
530
|
+
border: 1px solid #ddd;
|
|
531
|
+
border-radius: 4px;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.workspace-content {
|
|
535
|
+
text-align: center;
|
|
536
|
+
padding: 40px;
|
|
537
|
+
color: #666;
|
|
538
|
+
}
|
|
539
|
+
</style>
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## 样式
|
|
543
|
+
|
|
544
|
+
Tabs 组件使用以下 CSS 类:
|
|
545
|
+
|
|
546
|
+
```css
|
|
547
|
+
.uniface-tab-panel {
|
|
548
|
+
/* 主要的标签页容器 */
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.uniface-tabs-wrap {
|
|
552
|
+
/* 标签页头部容器 */
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.uniface-tabs-wrap.simple {
|
|
556
|
+
/* 简化样式变体 */
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.scroll-left, .scroll-right {
|
|
560
|
+
/* 滚动控制按钮 */
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.tabs-panel {
|
|
564
|
+
/* 标签页按钮容器 */
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.uniface-tab {
|
|
568
|
+
/* 单个标签页按钮 */
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.uniface-tab.active {
|
|
572
|
+
/* 活动标签页样式 */
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.tab-content {
|
|
576
|
+
/* 标签页内容区域 */
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.tab-refresh, .tab-action {
|
|
580
|
+
/* 标签页操作按钮(刷新、关闭) */
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## API 参考
|
|
585
|
+
|
|
586
|
+
### Tabs 组件属性
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
interface TabsProps {
|
|
590
|
+
class?: string; // 额外的 CSS 类
|
|
591
|
+
simple?: boolean; // 简化样式
|
|
592
|
+
textField?: string; // 标签页文本的字段名
|
|
593
|
+
style?: string; // 自定义样式
|
|
594
|
+
tabs: Array<any>; // 标签页数据数组
|
|
595
|
+
scrollStep?: number; // 滚动像素数
|
|
596
|
+
closable?: boolean | TabActionHandler; // 启用关闭
|
|
597
|
+
activeTab?: any; // 当前活动标签页
|
|
598
|
+
tabRender?: TabRender; // 自定义标签页渲染器
|
|
599
|
+
reloadHandler?: TabActionHandler; // 重新加载回调
|
|
600
|
+
closeHandler?: TabCloseHandler; // 关闭回调
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### 类型定义
|
|
605
|
+
|
|
606
|
+
```typescript
|
|
607
|
+
/**
|
|
608
|
+
* 标签页操作处理器函数
|
|
609
|
+
*/
|
|
610
|
+
export type TabActionHandler = (tab: any) => void;
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* 标签页关闭处理器函数 - 返回 false 阻止关闭
|
|
614
|
+
*/
|
|
615
|
+
export type TabCloseHandler = (tab: any) => Promise<boolean>;
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* 自定义标签页渲染组件
|
|
619
|
+
*/
|
|
620
|
+
export type TabRender = (tab: any) => any;
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
## 最佳实践
|
|
624
|
+
|
|
625
|
+
1. **一致的标签页数据** - 在所有标签页项目中使用一致的对象结构
|
|
626
|
+
2. **性能优化** - 避免在标签页渲染中进行繁重的计算,特别是有多个标签页时
|
|
627
|
+
3. **键盘导航** - 确保标签页可通过键盘导航访问
|
|
628
|
+
4. **加载状态** - 在获取标签页内容时显示加载指示器
|
|
629
|
+
5. **内存管理** - 在关闭标签页时清理资源
|
|
630
|
+
6. **视觉反馈** - 为活动、悬停和禁用状态提供清晰的视觉反馈
|
|
631
|
+
7. **移动端响应式** - 考虑标签页在较小屏幕上的行为
|
|
632
|
+
8. **内容管理** - 对标签页内容组件使用适当的生命周期管理
|
|
633
|
+
|
|
634
|
+
## 高级功能
|
|
635
|
+
|
|
636
|
+
### 程序化标签页控制
|
|
637
|
+
|
|
638
|
+
```svelte
|
|
639
|
+
<script lang="ts">
|
|
640
|
+
import Tabs from '@ticatec/uniface-element/Tabs';
|
|
641
|
+
|
|
642
|
+
let tabs = [...];
|
|
643
|
+
let activeTab = tabs[0];
|
|
644
|
+
let tabsRef: Tabs;
|
|
645
|
+
|
|
646
|
+
function switchToTab(tabId: string) {
|
|
647
|
+
const tab = tabs.find(t => t.id === tabId);
|
|
648
|
+
if (tab) {
|
|
649
|
+
activeTab = tab;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function addTab(tabData: any) {
|
|
654
|
+
tabs = [...tabs, tabData];
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function removeTab(tabId: string) {
|
|
658
|
+
tabs = tabs.filter(t => t.id !== tabId);
|
|
659
|
+
// 如果需要,更新活动标签页
|
|
660
|
+
if (activeTab.id === tabId && tabs.length > 0) {
|
|
661
|
+
activeTab = tabs[0];
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
</script>
|
|
665
|
+
|
|
666
|
+
<Tabs bind:this={tabsRef} bind:tabs bind:activeTab>
|
|
667
|
+
<!-- 标签页内容 -->
|
|
668
|
+
</Tabs>
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
## 与路由集成
|
|
672
|
+
|
|
673
|
+
Tabs 组件可以与客户端路由集成:
|
|
674
|
+
|
|
675
|
+
```svelte
|
|
676
|
+
<script lang="ts">
|
|
677
|
+
import { page } from '$app/stores';
|
|
678
|
+
import { goto } from '$app/navigation';
|
|
679
|
+
|
|
680
|
+
$: currentRoute = $page.route.id;
|
|
681
|
+
|
|
682
|
+
function handleTabChange(tab: any) {
|
|
683
|
+
goto(`/dashboard/${tab.route}`);
|
|
684
|
+
}
|
|
685
|
+
</script>
|
|
686
|
+
```
|