tang-ui-x 1.0.6 → 1.1.1
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/components/TForm/README.md +644 -0
- package/components/TForm/index.uvue +392 -0
- package/components/TForm/type.uts +80 -0
- package/components/TRadioButton/README.md +117 -0
- package/components/TRadioButton/index.uvue +69 -64
- package/index.uts +108 -107
- package/package.json +48 -47
- package/components/VbenFrom/index.uvue +0 -392
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
<script setup lang="uts">
|
|
2
|
+
import TRadioButton from '../TRadioButton/index.uvue'
|
|
3
|
+
import TCheckbox from '../TCheckbox/index.uvue'
|
|
4
|
+
import TSwitch from '../TSwitch/index.uvue'
|
|
5
|
+
import TRate from '../TRate/index.uvue'
|
|
6
|
+
import TSlider from '../TSlider/index.uvue'
|
|
7
|
+
import type { FormOption, FormSchema, TFormProps, ComponentProps } from './type.uts'
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(defineProps<TFormProps>(), {
|
|
10
|
+
labelWidth: '160rpx',
|
|
11
|
+
hideButtons: false,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const emit = defineEmits(['submit', 'reset'])
|
|
15
|
+
|
|
16
|
+
const model = defineModel<Record<string, any>>({ default: () => ({}) })
|
|
17
|
+
const errors = reactive<Record<string, string>>({})
|
|
18
|
+
|
|
19
|
+
const handlePlaceholder = (item: FormSchema): string => {
|
|
20
|
+
return item.componentProps?.placeholder || `请输入${item.label}`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const handleRange = (item: FormSchema) => {
|
|
24
|
+
const options = item.componentProps?.options as FormOption[] | undefined
|
|
25
|
+
return options?.map(o => o.label) || []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const getSelectLabel = (item: FormSchema) => {
|
|
29
|
+
const options = item.componentProps?.options as FormOption[] | undefined
|
|
30
|
+
const opt = options?.find(o => o.value === model.value[item.field])
|
|
31
|
+
return opt?.label || ''
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const onSelectChange = (e: any, item: FormSchema) => {
|
|
35
|
+
const index = e.detail.value as number
|
|
36
|
+
const options = item.componentProps?.options as FormOption[] | undefined
|
|
37
|
+
const value = options?.[index]?.value ?? ''
|
|
38
|
+
model.value[item.field] = value
|
|
39
|
+
validateField(item)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const onTimeChange = (e: any, item: FormSchema) => {
|
|
43
|
+
model.value[item.field] = e.detail.value
|
|
44
|
+
validateField(item)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const validateField = (item: FormSchema) => {
|
|
48
|
+
if (item.required && !model.value[item.field]) {
|
|
49
|
+
errors[item.field] = `请输入${item.label}`
|
|
50
|
+
} else {
|
|
51
|
+
delete errors[item.field]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const onRadioChange = (value: string | number, item: FormSchema) => {
|
|
56
|
+
model.value[item.field] = value
|
|
57
|
+
validateField(item)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const onCheckboxChange = (values: (string | number)[], item: FormSchema) => {
|
|
61
|
+
model.value[item.field] = values
|
|
62
|
+
validateField(item)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const onSwitchChange = (value: boolean, item: FormSchema) => {
|
|
66
|
+
model.value[item.field] = value
|
|
67
|
+
validateField(item)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const onRateChange = (value: number, item: FormSchema) => {
|
|
71
|
+
model.value[item.field] = value
|
|
72
|
+
validateField(item)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const onSliderChange = (value: number, item: FormSchema) => {
|
|
76
|
+
model.value[item.field] = value
|
|
77
|
+
validateField(item)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const onFormSubmit = async (e: UniFormSubmitEvent): Promise<{ valid: boolean, values: any }> => {
|
|
81
|
+
Object.keys(errors).forEach(k => delete errors[k])
|
|
82
|
+
|
|
83
|
+
let hasError = false
|
|
84
|
+
for (const item of props.schemas) {
|
|
85
|
+
validateField(item)
|
|
86
|
+
if (item.required && !model.value[item.field]) {
|
|
87
|
+
hasError = true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (hasError) {
|
|
92
|
+
console.warn('表单验证失败')
|
|
93
|
+
return { valid: false, values: null }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await emit('submit', model.value)
|
|
98
|
+
return { valid: true, values: model.value }
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error('表单提交失败:', err)
|
|
101
|
+
return { valid: false, values: null }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const onFormReset = () => {
|
|
106
|
+
Object.keys(model.value).forEach(k => (model.value[k] = ''))
|
|
107
|
+
Object.keys(errors).forEach(k => delete errors[k])
|
|
108
|
+
emit('reset')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
defineExpose({
|
|
112
|
+
submit: async () => {
|
|
113
|
+
return await onFormSubmit({} as UniFormSubmitEvent)
|
|
114
|
+
},
|
|
115
|
+
reset: () => {
|
|
116
|
+
onFormReset()
|
|
117
|
+
},
|
|
118
|
+
validate: () => {
|
|
119
|
+
Object.keys(errors).forEach(k => delete errors[k])
|
|
120
|
+
let hasError = false
|
|
121
|
+
for (const item of props.schemas) {
|
|
122
|
+
validateField(item)
|
|
123
|
+
if (item.required && !model.value[item.field]) {
|
|
124
|
+
hasError = true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return !hasError
|
|
128
|
+
},
|
|
129
|
+
getFormData: () => ({ ...model.value }),
|
|
130
|
+
getErrors: () => ({ ...errors })
|
|
131
|
+
})
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<template>
|
|
135
|
+
<view class="t-form">
|
|
136
|
+
<form @submit="onFormSubmit" @reset="onFormReset">
|
|
137
|
+
<view v-for="(item, index) in schemas" class="form-item" :key="index">
|
|
138
|
+
<view class="form-label" :style="{ width: labelWidth }">
|
|
139
|
+
<text>{{ item.label }}</text>
|
|
140
|
+
<text v-if="item.required" class="required">*</text>
|
|
141
|
+
</view>
|
|
142
|
+
|
|
143
|
+
<view class="form-control">
|
|
144
|
+
<!-- 自定义插槽 -->
|
|
145
|
+
<slot v-if="$slots[item.field]" :name="item.field" :item="item" :value="model[item.field]" :error="errors[item.field]"></slot>
|
|
146
|
+
|
|
147
|
+
<!-- 输入框 -->
|
|
148
|
+
<input v-else-if="item.component === 'Input'"
|
|
149
|
+
v-model="model[item.field]"
|
|
150
|
+
:placeholder="handlePlaceholder(item)"
|
|
151
|
+
:name="item.field"
|
|
152
|
+
class="input"
|
|
153
|
+
v-bind="item.componentProps || {}"
|
|
154
|
+
@input="validateField(item)" />
|
|
155
|
+
|
|
156
|
+
<!-- 数字输入 -->
|
|
157
|
+
<input v-else-if="item.component === 'InputNumber'"
|
|
158
|
+
v-model="model[item.field]"
|
|
159
|
+
:placeholder="handlePlaceholder(item)"
|
|
160
|
+
type="number"
|
|
161
|
+
:name="item.field"
|
|
162
|
+
class="input"
|
|
163
|
+
v-bind="item.componentProps || {}"
|
|
164
|
+
@input="validateField(item)" />
|
|
165
|
+
|
|
166
|
+
<!-- 文本域 -->
|
|
167
|
+
<textarea v-else-if="item.component === 'Textarea'"
|
|
168
|
+
v-model="model[item.field]"
|
|
169
|
+
:placeholder="handlePlaceholder(item)"
|
|
170
|
+
:name="item.field"
|
|
171
|
+
class="textarea"
|
|
172
|
+
v-bind="item.componentProps || {}"
|
|
173
|
+
@input="validateField(item)"></textarea>
|
|
174
|
+
|
|
175
|
+
<!-- 下拉选择 -->
|
|
176
|
+
<picker v-else-if="item.component === 'Select'"
|
|
177
|
+
mode="selector"
|
|
178
|
+
:name="item.field"
|
|
179
|
+
:range="handleRange(item)"
|
|
180
|
+
v-bind="item.componentProps || {}"
|
|
181
|
+
@change="onSelectChange($event, item)">
|
|
182
|
+
<view class="picker">
|
|
183
|
+
{{ getSelectLabel(item) || '请选择' }}
|
|
184
|
+
</view>
|
|
185
|
+
</picker>
|
|
186
|
+
|
|
187
|
+
<!-- 日期选择 -->
|
|
188
|
+
<picker v-else-if="item.component === 'Date'"
|
|
189
|
+
mode="date"
|
|
190
|
+
:name="item.field"
|
|
191
|
+
:value="model[item.field]"
|
|
192
|
+
v-bind="item.componentProps || {}"
|
|
193
|
+
@change="onTimeChange($event, item)">
|
|
194
|
+
<view class="picker">
|
|
195
|
+
{{ model[item.field] || '请选择日期' }}
|
|
196
|
+
</view>
|
|
197
|
+
</picker>
|
|
198
|
+
|
|
199
|
+
<!-- 时间选择 -->
|
|
200
|
+
<picker v-else-if="item.component === 'Time'"
|
|
201
|
+
mode="time"
|
|
202
|
+
:name="item.field"
|
|
203
|
+
:value="model[item.field]"
|
|
204
|
+
v-bind="item.componentProps || {}"
|
|
205
|
+
@change="onTimeChange($event, item)">
|
|
206
|
+
<view class="picker">
|
|
207
|
+
{{ model[item.field] || '请选择时间' }}
|
|
208
|
+
</view>
|
|
209
|
+
</picker>
|
|
210
|
+
|
|
211
|
+
<!-- 单选 -->
|
|
212
|
+
<view v-else-if="item.component === 'Radio'" class="radio-group">
|
|
213
|
+
<TRadioButton
|
|
214
|
+
v-for="opt in (item.componentProps?.options as FormOption[])"
|
|
215
|
+
:key="opt.value"
|
|
216
|
+
v-model="model[item.field]"
|
|
217
|
+
:label="opt.label"
|
|
218
|
+
:value="opt.value"
|
|
219
|
+
@change="onRadioChange(opt.value, item)" />
|
|
220
|
+
</view>
|
|
221
|
+
|
|
222
|
+
<!-- 多选 -->
|
|
223
|
+
<view v-else-if="item.component === 'Checkbox'" class="checkbox-group">
|
|
224
|
+
<view
|
|
225
|
+
v-for="opt in (item.componentProps?.options as FormOption[])"
|
|
226
|
+
:key="opt.value"
|
|
227
|
+
class="checkbox-item">
|
|
228
|
+
<TCheckbox
|
|
229
|
+
:checked="(model[item.field] || []).includes(opt.value)"
|
|
230
|
+
v-bind="item.componentProps || {}"
|
|
231
|
+
@change="(checked) => {
|
|
232
|
+
const values = model[item.field] || []
|
|
233
|
+
if (checked) {
|
|
234
|
+
values.push(opt.value)
|
|
235
|
+
} else {
|
|
236
|
+
const index = values.indexOf(opt.value)
|
|
237
|
+
if (index > -1) values.splice(index, 1)
|
|
238
|
+
}
|
|
239
|
+
onCheckboxChange(values, item)
|
|
240
|
+
}" />
|
|
241
|
+
<text class="checkbox-label">{{ opt.label }}</text>
|
|
242
|
+
</view>
|
|
243
|
+
</view>
|
|
244
|
+
|
|
245
|
+
<!-- 开关 -->
|
|
246
|
+
<TSwitch v-else-if="item.component === 'Switch'"
|
|
247
|
+
:checked="model[item.field]"
|
|
248
|
+
v-bind="item.componentProps || {}"
|
|
249
|
+
@change="onSwitchChange($event, item)" />
|
|
250
|
+
|
|
251
|
+
<!-- 评分 -->
|
|
252
|
+
<TRate v-else-if="item.component === 'Rate'"
|
|
253
|
+
:value="model[item.field] || 0"
|
|
254
|
+
v-bind="item.componentProps || {}"
|
|
255
|
+
@change="onRateChange($event, item)" />
|
|
256
|
+
|
|
257
|
+
<!-- 滑块 -->
|
|
258
|
+
<TSlider v-else-if="item.component === 'Slider'"
|
|
259
|
+
:value="model[item.field] || 0"
|
|
260
|
+
v-bind="item.componentProps || {}"
|
|
261
|
+
@change="onSliderChange($event, item)" />
|
|
262
|
+
</view>
|
|
263
|
+
|
|
264
|
+
<!-- 错误提示 -->
|
|
265
|
+
<view v-if="errors[item.field]" class="error-message">
|
|
266
|
+
<text>{{ errors[item.field] }}</text>
|
|
267
|
+
</view>
|
|
268
|
+
</view>
|
|
269
|
+
|
|
270
|
+
<!-- 按钮区域 -->
|
|
271
|
+
<view v-if="!hideButtons" class="form-footer">
|
|
272
|
+
<button class="btn btn-submit" form-type="submit">提交</button>
|
|
273
|
+
<button class="btn btn-reset" form-type="reset">重置</button>
|
|
274
|
+
</view>
|
|
275
|
+
</form>
|
|
276
|
+
</view>
|
|
277
|
+
</template>
|
|
278
|
+
|
|
279
|
+
<style lang="scss" scoped>
|
|
280
|
+
.t-form {
|
|
281
|
+
padding: 32rpx;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.form-item {
|
|
285
|
+
margin-bottom: 32rpx;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.form-label {
|
|
289
|
+
display: flex;
|
|
290
|
+
flex-direction: row;
|
|
291
|
+
align-items: center;
|
|
292
|
+
margin-bottom: 16rpx;
|
|
293
|
+
font-size: 28rpx;
|
|
294
|
+
color: #333;
|
|
295
|
+
font-weight: 500;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.required {
|
|
299
|
+
color: #ff4d4f;
|
|
300
|
+
margin-left: 4rpx;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.form-control {
|
|
304
|
+
width: 100%;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.input,
|
|
308
|
+
.textarea,
|
|
309
|
+
.picker {
|
|
310
|
+
width: 100%;
|
|
311
|
+
padding: 20rpx 24rpx;
|
|
312
|
+
font-size: 28rpx;
|
|
313
|
+
color: #333;
|
|
314
|
+
background-color: #f5f5f5;
|
|
315
|
+
border-radius: 8rpx;
|
|
316
|
+
border: 1rpx solid #e0e0e0;
|
|
317
|
+
transition: all 0.3s;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.input:focus,
|
|
321
|
+
.textarea:focus {
|
|
322
|
+
background-color: #fff;
|
|
323
|
+
border-color: #007aff;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.textarea {
|
|
327
|
+
min-height: 120rpx;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.picker {
|
|
331
|
+
display: flex;
|
|
332
|
+
align-items: center;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.radio-group,
|
|
336
|
+
.checkbox-group {
|
|
337
|
+
display: flex;
|
|
338
|
+
flex-direction: column;
|
|
339
|
+
gap: 16rpx;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.checkbox-item {
|
|
343
|
+
display: flex;
|
|
344
|
+
flex-direction: row;
|
|
345
|
+
align-items: center;
|
|
346
|
+
gap: 16rpx;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.checkbox-label {
|
|
350
|
+
font-size: 28rpx;
|
|
351
|
+
color: #333;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.error-message {
|
|
355
|
+
margin-top: 8rpx;
|
|
356
|
+
font-size: 24rpx;
|
|
357
|
+
color: #ff4d4f;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.form-footer {
|
|
361
|
+
display: flex;
|
|
362
|
+
flex-direction: row;
|
|
363
|
+
gap: 24rpx;
|
|
364
|
+
margin-top: 48rpx;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.btn {
|
|
368
|
+
flex: 1;
|
|
369
|
+
height: 88rpx;
|
|
370
|
+
line-height: 88rpx;
|
|
371
|
+
text-align: center;
|
|
372
|
+
font-size: 32rpx;
|
|
373
|
+
border-radius: 8rpx;
|
|
374
|
+
transition: all 0.3s;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.btn-submit {
|
|
378
|
+
background-color: #007aff;
|
|
379
|
+
color: #fff;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.btn-reset {
|
|
383
|
+
background-color: #fff;
|
|
384
|
+
color: #007aff;
|
|
385
|
+
border: 1rpx solid #007aff;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.btn:active {
|
|
389
|
+
opacity: 0.7;
|
|
390
|
+
transform: scale(0.98);
|
|
391
|
+
}
|
|
392
|
+
</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 表单选项类型
|
|
3
|
+
*/
|
|
4
|
+
export type FormOption = {
|
|
5
|
+
label: string
|
|
6
|
+
value: string | number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 组件通用属性
|
|
11
|
+
*/
|
|
12
|
+
export type ComponentProps = {
|
|
13
|
+
/** 占位符 */
|
|
14
|
+
placeholder?: string
|
|
15
|
+
/** 是否禁用 */
|
|
16
|
+
disabled?: boolean
|
|
17
|
+
/** 选项列表(用于 select、radio、checkbox) */
|
|
18
|
+
options?: FormOption[]
|
|
19
|
+
/** 输入类型(用于 input) */
|
|
20
|
+
type?: string
|
|
21
|
+
/** 最大长度(用于 input、textarea) */
|
|
22
|
+
maxlength?: number
|
|
23
|
+
/** 最小值(用于 number、slider) */
|
|
24
|
+
min?: number
|
|
25
|
+
/** 最大值(用于 number、slider、rate) */
|
|
26
|
+
max?: number
|
|
27
|
+
/** 步长(用于 slider) */
|
|
28
|
+
step?: number
|
|
29
|
+
/** 是否自动聚焦(用于 input、textarea) */
|
|
30
|
+
focus?: boolean
|
|
31
|
+
/** 确认按钮文字(用于 input) */
|
|
32
|
+
confirmType?: string
|
|
33
|
+
/** 是否自动高度(用于 textarea) */
|
|
34
|
+
autoHeight?: boolean
|
|
35
|
+
/** 是否显示确认栏(用于 textarea) */
|
|
36
|
+
showConfirmBar?: boolean
|
|
37
|
+
/** 开始日期(用于 date) */
|
|
38
|
+
start?: string
|
|
39
|
+
/** 结束日期(用于 date) */
|
|
40
|
+
end?: string
|
|
41
|
+
/** 激活颜色(用于 switch) */
|
|
42
|
+
color?: string
|
|
43
|
+
/** 是否允许半星(用于 rate) */
|
|
44
|
+
allowHalf?: boolean
|
|
45
|
+
/** 是否显示值(用于 slider) */
|
|
46
|
+
showValue?: boolean
|
|
47
|
+
/** 其他扩展属性 */
|
|
48
|
+
[key: string]: any
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 表单字段配置
|
|
53
|
+
*/
|
|
54
|
+
export type FormSchema = {
|
|
55
|
+
/** 字段名 */
|
|
56
|
+
field: string
|
|
57
|
+
/** 标签文本 */
|
|
58
|
+
label: string
|
|
59
|
+
/** 组件类型 */
|
|
60
|
+
component: 'Input' | 'Textarea' | 'Select' | 'Date' | 'Time' | 'Radio' | 'Checkbox' | 'Switch' | 'Rate' | 'Slider' | 'InputNumber'
|
|
61
|
+
/** 是否必填 */
|
|
62
|
+
required?: boolean
|
|
63
|
+
/** 组件属性 */
|
|
64
|
+
componentProps?: ComponentProps
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 表单组件属性
|
|
69
|
+
*/
|
|
70
|
+
export type TFormProps = {
|
|
71
|
+
/** 表单配置 */
|
|
72
|
+
schemas: FormSchema[]
|
|
73
|
+
/** 标签宽度 */
|
|
74
|
+
labelWidth?: string
|
|
75
|
+
/** 是否隐藏默认按钮 */
|
|
76
|
+
hideButtons?: boolean
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 导出所有类型
|
|
80
|
+
export { FormOption, ComponentProps, FormSchema, TFormProps }
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# TRadioButton 单选按钮
|
|
2
|
+
|
|
3
|
+
单选按钮组件,支持单个按钮和选项组两种使用方式。
|
|
4
|
+
|
|
5
|
+
## 基础用法
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<TRadioButton v-model="value" value="option1">选项一</TRadioButton>
|
|
10
|
+
<TRadioButton v-model="value" value="option2">选项二</TRadioButton>
|
|
11
|
+
<TRadioButton v-model="value" value="option3">选项三</TRadioButton>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import { ref } from 'vue'
|
|
16
|
+
const value = ref('option1')
|
|
17
|
+
</script>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 选项组模式
|
|
21
|
+
|
|
22
|
+
通过 `options` 属性传入选项数组,自动渲染多个单选按钮。
|
|
23
|
+
|
|
24
|
+
```vue
|
|
25
|
+
<template>
|
|
26
|
+
<TRadioButton
|
|
27
|
+
v-model="value"
|
|
28
|
+
:options="[
|
|
29
|
+
{ label: '选项一', value: 'option1' },
|
|
30
|
+
{ label: '选项二', value: 'option2' },
|
|
31
|
+
{ label: '选项三', value: 'option3' }
|
|
32
|
+
]"
|
|
33
|
+
/>
|
|
34
|
+
</template>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 禁用状态
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<TRadioButton v-model="value" value="option1" disabled>禁用选项</TRadioButton>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 不同尺寸
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<TRadioButton v-model="value" value="small" size="small">小尺寸</TRadioButton>
|
|
47
|
+
<TRadioButton v-model="value" value="medium" size="medium">中等尺寸</TRadioButton>
|
|
48
|
+
<TRadioButton v-model="value" value="large" size="large">大尺寸</TRadioButton>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 自定义颜色
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<TRadioButton
|
|
55
|
+
v-model="value"
|
|
56
|
+
value="option1"
|
|
57
|
+
activeColor="#f56c6c"
|
|
58
|
+
inactiveColor="#909399"
|
|
59
|
+
>
|
|
60
|
+
自定义颜色
|
|
61
|
+
</TRadioButton>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Props
|
|
65
|
+
|
|
66
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
67
|
+
|------|------|------|--------|
|
|
68
|
+
| modelValue (v-model) | 绑定值 | `string \| number` | - |
|
|
69
|
+
| value | 单选按钮的值 | `string \| number` | - |
|
|
70
|
+
| label | 显示的标签文本 | `string` | - |
|
|
71
|
+
| options | 选项组模式的选项列表 | `FormOption[]` | `[]` |
|
|
72
|
+
| size | 按钮尺寸 | `'small' \| 'medium' \| 'large'` | `'medium'` |
|
|
73
|
+
| activeColor | 激活状态颜色 | `string` | `'#00bba7'` |
|
|
74
|
+
| inactiveColor | 非激活状态颜色 | `string` | `'#666666'` |
|
|
75
|
+
| disabled | 是否禁用 | `boolean` | `false` |
|
|
76
|
+
| checked | 是否选中(仅单个按钮模式) | `boolean` | `false` |
|
|
77
|
+
| name | 原生 name 属性 | `string` | - |
|
|
78
|
+
|
|
79
|
+
## Events
|
|
80
|
+
|
|
81
|
+
| 事件名 | 说明 | 回调参数 |
|
|
82
|
+
|--------|------|----------|
|
|
83
|
+
| change | 选中值改变时触发 | `(value: string \| number)` |
|
|
84
|
+
|
|
85
|
+
## FormOption 类型
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
type FormOption = {
|
|
89
|
+
label: string
|
|
90
|
+
value: string | number
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 在 TForm 中使用
|
|
95
|
+
|
|
96
|
+
TRadioButton 可以在 TForm 组件中使用:
|
|
97
|
+
|
|
98
|
+
```vue
|
|
99
|
+
<TForm v-model="formData" :schemas="schemas" />
|
|
100
|
+
|
|
101
|
+
<script setup>
|
|
102
|
+
const schemas = [
|
|
103
|
+
{
|
|
104
|
+
field: 'gender',
|
|
105
|
+
label: '性别',
|
|
106
|
+
component: 'Radio',
|
|
107
|
+
required: true,
|
|
108
|
+
componentProps: {
|
|
109
|
+
options: [
|
|
110
|
+
{ label: '男', value: 'male' },
|
|
111
|
+
{ label: '女', value: 'female' }
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
</script>
|
|
117
|
+
```
|