perf: 优化useVbenForm样式 (#6611)
* perf(style): 优化useVbenForm垂直布局 actions 样式 * perf(style): 优化useVbenForm actions 布局样式 - 操作按钮组显示位置 ``` actionPosition?: 'center' | 'left' | 'right'; ``` - 操作按钮组的样式 ``` actionType?: 'block' | 'inline' inline: 行类显示,block: 新一行单独显示 ``` * perf: 优化useVbenForm actions 布局样式 删除 actionType 增加 actionLayout - actionLayout?: 'inline' | 'newLine' | 'rowEnd'; - newLine: 在新行显示。rowEnd: 在行内显示,靠右对齐(默认)。inline: 使用grid默认样式 - 删除无用代码 queryFormStyle * perf: 优化useVbenForm使用案例 * perf: 优化form组件样式 去掉padding,改为gap * docs: update vben-form.md * fix: 修复FormMessage位置 * perf: Avoid direct mutation of props object. - props.actionLayout = props.actionLayout || 'rowEnd'; - props.actionPosition = props.actionPosition || 'right'; + const actionLayout = props.actionLayout || 'rowEnd'; + const actionPosition = props.actionPosition || 'right'; Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: 修复 wrapperClass 权重 * fix: 全局搜索结果不匹配 #6603 * fix: 避免FormMessage溢出 --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>pull/201/head^2
parent
b93e22c45a
commit
9fc594434f
|
@ -308,6 +308,8 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
|
||||||
| showCollapseButton | 是否显示折叠按钮 | `boolean` | `false` |
|
| showCollapseButton | 是否显示折叠按钮 | `boolean` | `false` |
|
||||||
| wrapperClass | 表单的布局,基于tailwindcss | `any` | - |
|
| wrapperClass | 表单的布局,基于tailwindcss | `any` | - |
|
||||||
| actionWrapperClass | 表单操作区域class | `any` | - |
|
| actionWrapperClass | 表单操作区域class | `any` | - |
|
||||||
|
| actionLayout | 表单操作按钮位置 | `'newLine' \| 'rowEnd' \| 'inline'` | `rowEnd` |
|
||||||
|
| actionPosition | 表单操作按钮对齐方式 | `'left' \| 'center' \| 'right'` | `right` |
|
||||||
| handleReset | 表单重置回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
|
| handleReset | 表单重置回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
|
||||||
| handleSubmit | 表单提交回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
|
| handleSubmit | 表单提交回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
|
||||||
| handleValuesChange | 表单值变化回调 | `(values: Record<string, any>, fieldsChanged: string[]) => void` | - |
|
| handleValuesChange | 表单值变化回调 | `(values: Record<string, any>, fieldsChanged: string[]) => void` | - |
|
||||||
|
|
|
@ -34,17 +34,6 @@ const submitButtonOptions = computed(() => {
|
||||||
// return !!unref(rootProps).showCollapseButton;
|
// return !!unref(rootProps).showCollapseButton;
|
||||||
// });
|
// });
|
||||||
|
|
||||||
const queryFormStyle = computed(() => {
|
|
||||||
if (!unref(rootProps).actionWrapperClass) {
|
|
||||||
return {
|
|
||||||
'grid-column': `-2 / -1`,
|
|
||||||
marginLeft: 'auto',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
async function handleSubmit(e: Event) {
|
async function handleSubmit(e: Event) {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
e?.stopPropagation();
|
e?.stopPropagation();
|
||||||
|
@ -86,22 +75,59 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const actionWrapperClass = computed(() => {
|
||||||
|
const props = unref(rootProps);
|
||||||
|
const actionLayout = props.actionLayout || 'rowEnd';
|
||||||
|
const actionPosition = props.actionPosition || 'right';
|
||||||
|
|
||||||
|
const cls = [
|
||||||
|
'flex',
|
||||||
|
'w-full',
|
||||||
|
'items-center',
|
||||||
|
'gap-3',
|
||||||
|
props.compact ? 'pb-2' : 'pb-4',
|
||||||
|
props.layout === 'vertical' ? 'self-end' : 'self-center',
|
||||||
|
props.actionWrapperClass,
|
||||||
|
];
|
||||||
|
|
||||||
|
switch (actionLayout) {
|
||||||
|
case 'newLine': {
|
||||||
|
cls.push('col-span-full');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'rowEnd': {
|
||||||
|
cls.push('col-[-2/-1]');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 'inline' 不需要额外类名,保持默认
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (actionPosition) {
|
||||||
|
case 'center': {
|
||||||
|
cls.push('justify-center');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'left': {
|
||||||
|
cls.push('justify-start');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// case 'right': 默认右对齐
|
||||||
|
cls.push('justify-end');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cls.join(' ');
|
||||||
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
handleReset,
|
handleReset,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="cn(actionWrapperClass)">
|
||||||
:class="
|
|
||||||
cn(
|
|
||||||
'col-span-full w-full text-right',
|
|
||||||
rootProps.compact ? 'pb-2' : 'pb-6',
|
|
||||||
rootProps.actionWrapperClass,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
:style="queryFormStyle"
|
|
||||||
>
|
|
||||||
<template v-if="rootProps.actionButtonsReverse">
|
<template v-if="rootProps.actionButtonsReverse">
|
||||||
<!-- 提交按钮前 -->
|
<!-- 提交按钮前 -->
|
||||||
<slot name="submit-before"></slot>
|
<slot name="submit-before"></slot>
|
||||||
|
@ -109,7 +135,6 @@ defineExpose({
|
||||||
<component
|
<component
|
||||||
:is="COMPONENT_MAP.PrimaryButton"
|
:is="COMPONENT_MAP.PrimaryButton"
|
||||||
v-if="submitButtonOptions.show"
|
v-if="submitButtonOptions.show"
|
||||||
class="ml-3"
|
|
||||||
type="button"
|
type="button"
|
||||||
@click="handleSubmit"
|
@click="handleSubmit"
|
||||||
v-bind="submitButtonOptions"
|
v-bind="submitButtonOptions"
|
||||||
|
@ -124,7 +149,6 @@ defineExpose({
|
||||||
<component
|
<component
|
||||||
:is="COMPONENT_MAP.DefaultButton"
|
:is="COMPONENT_MAP.DefaultButton"
|
||||||
v-if="resetButtonOptions.show"
|
v-if="resetButtonOptions.show"
|
||||||
class="ml-3"
|
|
||||||
type="button"
|
type="button"
|
||||||
@click="handleReset"
|
@click="handleReset"
|
||||||
v-bind="resetButtonOptions"
|
v-bind="resetButtonOptions"
|
||||||
|
@ -139,7 +163,6 @@ defineExpose({
|
||||||
<component
|
<component
|
||||||
:is="COMPONENT_MAP.PrimaryButton"
|
:is="COMPONENT_MAP.PrimaryButton"
|
||||||
v-if="submitButtonOptions.show"
|
v-if="submitButtonOptions.show"
|
||||||
class="ml-3"
|
|
||||||
type="button"
|
type="button"
|
||||||
@click="handleSubmit"
|
@click="handleSubmit"
|
||||||
v-bind="submitButtonOptions"
|
v-bind="submitButtonOptions"
|
||||||
|
@ -152,9 +175,9 @@ defineExpose({
|
||||||
<slot name="expand-before"></slot>
|
<slot name="expand-before"></slot>
|
||||||
|
|
||||||
<VbenExpandableArrow
|
<VbenExpandableArrow
|
||||||
|
class="ml-[-0.3em]"
|
||||||
v-if="rootProps.showCollapseButton"
|
v-if="rootProps.showCollapseButton"
|
||||||
v-model:model-value="collapsed"
|
v-model:model-value="collapsed"
|
||||||
class="ml-2"
|
|
||||||
>
|
>
|
||||||
<span>{{ collapsed ? $t('expand') : $t('collapse') }}</span>
|
<span>{{ collapsed ? $t('expand') : $t('collapse') }}</span>
|
||||||
</VbenExpandableArrow>
|
</VbenExpandableArrow>
|
||||||
|
|
|
@ -295,7 +295,7 @@ onUnmounted(() => {
|
||||||
'form-is-required': shouldRequired,
|
'form-is-required': shouldRequired,
|
||||||
'flex-col': isVertical,
|
'flex-col': isVertical,
|
||||||
'flex-row items-center': !isVertical,
|
'flex-row items-center': !isVertical,
|
||||||
'pb-6': !compact,
|
'pb-4': !compact,
|
||||||
'pb-2': compact,
|
'pb-2': compact,
|
||||||
}"
|
}"
|
||||||
class="relative flex"
|
class="relative flex"
|
||||||
|
@ -386,7 +386,7 @@ onUnmounted(() => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Transition name="slide-up" v-if="!compact">
|
<Transition name="slide-up" v-if="!compact">
|
||||||
<FormMessage class="absolute bottom-1" />
|
<FormMessage class="absolute" />
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
|
@ -41,6 +41,16 @@ const emits = defineEmits<{
|
||||||
submit: [event: any];
|
submit: [event: any];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const wrapperClass = computed(() => {
|
||||||
|
const cls = ['flex flex-col'];
|
||||||
|
if (props.layout === 'vertical') {
|
||||||
|
cls.push(props.compact ? 'gap-x-2' : 'gap-x-4');
|
||||||
|
} else {
|
||||||
|
cls.push('gap-2');
|
||||||
|
}
|
||||||
|
return cn(...cls, props.wrapperClass);
|
||||||
|
});
|
||||||
|
|
||||||
provideFormRenderProps(props);
|
provideFormRenderProps(props);
|
||||||
|
|
||||||
const { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);
|
const { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);
|
||||||
|
|
|
@ -354,6 +354,15 @@ export interface VbenFormProps<
|
||||||
* 操作按钮是否反转(提交按钮前置)
|
* 操作按钮是否反转(提交按钮前置)
|
||||||
*/
|
*/
|
||||||
actionButtonsReverse?: boolean;
|
actionButtonsReverse?: boolean;
|
||||||
|
/**
|
||||||
|
* 操作按钮组的样式
|
||||||
|
* newLine: 在新行显示。rowEnd: 在行内显示,靠右对齐(默认)。inline: 使用grid默认样式
|
||||||
|
*/
|
||||||
|
actionLayout?: 'inline' | 'newLine' | 'rowEnd';
|
||||||
|
/**
|
||||||
|
* 操作按钮组显示位置,默认靠右显示
|
||||||
|
*/
|
||||||
|
actionPosition?: 'center' | 'left' | 'right';
|
||||||
/**
|
/**
|
||||||
* 表单操作区域class
|
* 表单操作区域class
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -98,7 +98,7 @@ async function handleEnter() {
|
||||||
}
|
}
|
||||||
const to = result[index];
|
const to = result[index];
|
||||||
if (to) {
|
if (to) {
|
||||||
searchHistory.value.push(to);
|
searchHistory.value = uniqueByField([...searchHistory.value, to], 'path');
|
||||||
handleClose();
|
handleClose();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
if (isHttpUrl(to.path)) {
|
if (isHttpUrl(to.path)) {
|
||||||
|
|
|
@ -125,6 +125,70 @@ const [QueryForm1] = useVbenForm({
|
||||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [QueryForm2] = useVbenForm({
|
||||||
|
// 操作按钮组 newLine: 在新行显示。rowEnd: 在行内显示,靠右对齐(默认)。inline: 使用grid默认样式
|
||||||
|
actionLayout: 'newLine',
|
||||||
|
actionPosition: 'left', // 操作按钮组在左侧显示
|
||||||
|
// 默认折叠
|
||||||
|
collapsed: true,
|
||||||
|
collapsedRows: 3,
|
||||||
|
// 所有表单项共用,可单独在表单内覆盖
|
||||||
|
commonConfig: {
|
||||||
|
// 所有表单项
|
||||||
|
componentProps: {
|
||||||
|
class: 'w-full',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 提交函数
|
||||||
|
handleSubmit: onSubmit,
|
||||||
|
// 垂直布局,label和input在不同行,值为vertical
|
||||||
|
// 水平布局,label和input在同一行
|
||||||
|
layout: 'vertical',
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
// 组件需要在 #/adapter.ts内注册,并加上类型
|
||||||
|
component: 'Input',
|
||||||
|
// 对应组件的参数
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户名',
|
||||||
|
},
|
||||||
|
// 字段名
|
||||||
|
fieldName: 'username',
|
||||||
|
// 界面显示的label
|
||||||
|
label: '字符串',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'InputPassword',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入密码',
|
||||||
|
},
|
||||||
|
fieldName: 'password',
|
||||||
|
label: '密码',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入',
|
||||||
|
},
|
||||||
|
fieldName: 'number',
|
||||||
|
label: '数字(带后缀)',
|
||||||
|
suffix: () => '¥',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: 'DatePicker',
|
||||||
|
fieldName: 'datePicker',
|
||||||
|
label: '日期选择框',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 是否可展开
|
||||||
|
showCollapseButton: true,
|
||||||
|
submitButtonOptions: {
|
||||||
|
content: '查询',
|
||||||
|
},
|
||||||
|
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
||||||
|
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
||||||
|
});
|
||||||
|
|
||||||
function onSubmit(values: Record<string, any>) {
|
function onSubmit(values: Record<string, any>) {
|
||||||
message.success({
|
message.success({
|
||||||
content: `form values: ${JSON.stringify(values)}`,
|
content: `form values: ${JSON.stringify(values)}`,
|
||||||
|
@ -140,6 +204,11 @@ function onSubmit(values: Record<string, any>) {
|
||||||
<Card class="mb-5" title="查询表单,默认展开">
|
<Card class="mb-5" title="查询表单,默认展开">
|
||||||
<QueryForm />
|
<QueryForm />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Card class="mb-5" title="查询表单,默认展开,垂直布局">
|
||||||
|
<QueryForm2 />
|
||||||
|
</Card>
|
||||||
|
|
||||||
<Card title="查询表单,默认折叠,折叠时保留2行">
|
<Card title="查询表单,默认折叠,折叠时保留2行">
|
||||||
<QueryForm1 />
|
<QueryForm1 />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
Loading…
Reference in New Issue