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` |
|
||||
| wrapperClass | 表单的布局,基于tailwindcss | `any` | - |
|
||||
| actionWrapperClass | 表单操作区域class | `any` | - |
|
||||
| actionLayout | 表单操作按钮位置 | `'newLine' \| 'rowEnd' \| 'inline'` | `rowEnd` |
|
||||
| actionPosition | 表单操作按钮对齐方式 | `'left' \| 'center' \| 'right'` | `right` |
|
||||
| handleReset | 表单重置回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
|
||||
| handleSubmit | 表单提交回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
|
||||
| handleValuesChange | 表单值变化回调 | `(values: Record<string, any>, fieldsChanged: string[]) => void` | - |
|
||||
|
|
|
@ -34,17 +34,6 @@ const submitButtonOptions = computed(() => {
|
|||
// return !!unref(rootProps).showCollapseButton;
|
||||
// });
|
||||
|
||||
const queryFormStyle = computed(() => {
|
||||
if (!unref(rootProps).actionWrapperClass) {
|
||||
return {
|
||||
'grid-column': `-2 / -1`,
|
||||
marginLeft: 'auto',
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e?.preventDefault();
|
||||
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({
|
||||
handleReset,
|
||||
handleSubmit,
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'col-span-full w-full text-right',
|
||||
rootProps.compact ? 'pb-2' : 'pb-6',
|
||||
rootProps.actionWrapperClass,
|
||||
)
|
||||
"
|
||||
:style="queryFormStyle"
|
||||
>
|
||||
<div :class="cn(actionWrapperClass)">
|
||||
<template v-if="rootProps.actionButtonsReverse">
|
||||
<!-- 提交按钮前 -->
|
||||
<slot name="submit-before"></slot>
|
||||
|
@ -109,7 +135,6 @@ defineExpose({
|
|||
<component
|
||||
:is="COMPONENT_MAP.PrimaryButton"
|
||||
v-if="submitButtonOptions.show"
|
||||
class="ml-3"
|
||||
type="button"
|
||||
@click="handleSubmit"
|
||||
v-bind="submitButtonOptions"
|
||||
|
@ -124,7 +149,6 @@ defineExpose({
|
|||
<component
|
||||
:is="COMPONENT_MAP.DefaultButton"
|
||||
v-if="resetButtonOptions.show"
|
||||
class="ml-3"
|
||||
type="button"
|
||||
@click="handleReset"
|
||||
v-bind="resetButtonOptions"
|
||||
|
@ -139,7 +163,6 @@ defineExpose({
|
|||
<component
|
||||
:is="COMPONENT_MAP.PrimaryButton"
|
||||
v-if="submitButtonOptions.show"
|
||||
class="ml-3"
|
||||
type="button"
|
||||
@click="handleSubmit"
|
||||
v-bind="submitButtonOptions"
|
||||
|
@ -152,9 +175,9 @@ defineExpose({
|
|||
<slot name="expand-before"></slot>
|
||||
|
||||
<VbenExpandableArrow
|
||||
class="ml-[-0.3em]"
|
||||
v-if="rootProps.showCollapseButton"
|
||||
v-model:model-value="collapsed"
|
||||
class="ml-2"
|
||||
>
|
||||
<span>{{ collapsed ? $t('expand') : $t('collapse') }}</span>
|
||||
</VbenExpandableArrow>
|
||||
|
|
|
@ -295,7 +295,7 @@ onUnmounted(() => {
|
|||
'form-is-required': shouldRequired,
|
||||
'flex-col': isVertical,
|
||||
'flex-row items-center': !isVertical,
|
||||
'pb-6': !compact,
|
||||
'pb-4': !compact,
|
||||
'pb-2': compact,
|
||||
}"
|
||||
class="relative flex"
|
||||
|
@ -386,7 +386,7 @@ onUnmounted(() => {
|
|||
</div>
|
||||
|
||||
<Transition name="slide-up" v-if="!compact">
|
||||
<FormMessage class="absolute bottom-1" />
|
||||
<FormMessage class="absolute" />
|
||||
</Transition>
|
||||
</div>
|
||||
</FormItem>
|
||||
|
|
|
@ -41,6 +41,16 @@ const emits = defineEmits<{
|
|||
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);
|
||||
|
||||
const { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);
|
||||
|
|
|
@ -354,6 +354,15 @@ export interface VbenFormProps<
|
|||
* 操作按钮是否反转(提交按钮前置)
|
||||
*/
|
||||
actionButtonsReverse?: boolean;
|
||||
/**
|
||||
* 操作按钮组的样式
|
||||
* newLine: 在新行显示。rowEnd: 在行内显示,靠右对齐(默认)。inline: 使用grid默认样式
|
||||
*/
|
||||
actionLayout?: 'inline' | 'newLine' | 'rowEnd';
|
||||
/**
|
||||
* 操作按钮组显示位置,默认靠右显示
|
||||
*/
|
||||
actionPosition?: 'center' | 'left' | 'right';
|
||||
/**
|
||||
* 表单操作区域class
|
||||
*/
|
||||
|
|
|
@ -98,7 +98,7 @@ async function handleEnter() {
|
|||
}
|
||||
const to = result[index];
|
||||
if (to) {
|
||||
searchHistory.value.push(to);
|
||||
searchHistory.value = uniqueByField([...searchHistory.value, to], 'path');
|
||||
handleClose();
|
||||
await nextTick();
|
||||
if (isHttpUrl(to.path)) {
|
||||
|
|
|
@ -125,6 +125,70 @@ const [QueryForm1] = useVbenForm({
|
|||
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>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
|
@ -140,6 +204,11 @@ function onSubmit(values: Record<string, any>) {
|
|||
<Card class="mb-5" title="查询表单,默认展开">
|
||||
<QueryForm />
|
||||
</Card>
|
||||
|
||||
<Card class="mb-5" title="查询表单,默认展开,垂直布局">
|
||||
<QueryForm2 />
|
||||
</Card>
|
||||
|
||||
<Card title="查询表单,默认折叠,折叠时保留2行">
|
||||
<QueryForm1 />
|
||||
</Card>
|
||||
|
|
Loading…
Reference in New Issue