前端交互规范(Web 端)
适用于基于 Vue + Element Plus 的中后台管理系统,共 20 条交互规范。
一、布局与展示
1. Table 列表页一屏显示
列表页不允许出现页面级竖向滚动条,筛选区 + 表格必须在一屏内完整展示。
const filterFormRef = ref<HTMLElement>()
const tableHeight = ref(0)
function calcTableHeight() {
const filterH = filterFormRef.value?.offsetHeight ?? 0
// 根据实际布局减去 header、padding 等固定高度
tableHeight.value = window.innerHeight - filterH - OTHER_FIXED_HEIGHT
}
onMounted(() => {
calcTableHeight()
window.addEventListener('resize', calcTableHeight)
})
onUnmounted(() => {
window.removeEventListener('resize', calcTableHeight)
})
<el-table :data="tableData" :height="tableHeight">
<!-- columns -->
</el-table>
18. 表格操作列固定右侧
操作列使用 fixed="right",横向滚动时操作按钮始终可见。
<el-table-column label="操作" fixed="right" width="200">
<template #default="{ row }">
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
19. 长文本省略 + Tooltip
表格单元格长文本使用 show-overflow-tooltip,保持列宽整齐,悬浮可查看完整内容。
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
二、弹窗与表单
2. 弹窗禁止点击遮罩层关闭
所有弹窗必须设置 close-on-click-modal="false",防止用户误触遮罩层导致数据丢失。
<el-dialog
v-model="dialogVisible"
title="新增数据"
:close-on-click-modal="false"
width="600px"
>
<!-- form content -->
</el-dialog>
9. 弹窗表单提交前必须校验
提交前调用 formRef.validate(),校验不通过不发起请求。
async function handleSubmit() {
const valid = await formRef.value?.validate().catch(() => false)
if (!valid) return
// 发起请求
}
15. 弹窗打开时重置表单
弹窗每次打开必须重置表单数据和校验状态,避免上次数据残留。
function openDialog(row?: RowType) {
nextTick(() => {
formRef.value?.resetFields()
if (row) {
Object.assign(formData, row)
}
})
dialogVisible.value = true
}
11. 弹窗关闭前变更确认
弹窗内表单有修改时,关闭前弹出二次确认"是否放弃修改?"。
function handleDialogClose(done: () => void) {
if (isFormDirty.value) {
ElMessageBox.confirm('表单已修改,确定放弃当前编辑内容吗?', '提示', {
type: 'warning',
}).then(() => done()).catch(() => {})
} else {
done()
}
}
<el-dialog :before-close="handleDialogClose">
三、防重复提交
3. 流程操作函数节流 + 确认弹窗拦截
新增、完成等流程操作使用 throttle 防止多次点击生成重复数据。
方式一:throttle 节流
import { throttle } from 'lodash'
const handleSubmit = throttle(() => {
// 业务逻辑
}, 1000, { trailing: false })
方式二:$confirm + beforeClose 模式(推荐用于关键流程操作)
function handleConfirm() {
ElMessageBox.confirm(
'确认执行此操作?一旦确认将不可撤回',
'提示',
{
type: 'warning',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true
instance.confirmButtonText = '执行中...'
submitApi().finally(() => {
setTimeout(() => {
instance.confirmButtonLoading = false
done()
}, 300)
})
} else {
done()
}
},
}
).then(() => {
getList()
ElMessage.success('操作成功')
}).catch(() => {})
}
10. 提交按钮 Loading 状态
提交/保存按钮在请求期间设为 loading,请求完成后恢复,给用户明确的视觉反馈。
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
确 定
</el-button>
const submitLoading = ref(false)
async function handleSubmit() {
submitLoading.value = true
try {
await submitApi(formData)
ElMessage.success('提交成功')
dialogVisible.value = false
getList()
} finally {
submitLoading.value = false
}
}
四、输入与筛选
4. 下拉框必须支持搜索过滤
所有 el-select 加上 filterable 属性,当选项较多时允许用户键入关键字快速定位。
<el-select v-model="formData.type" filterable placeholder="请选择" clearable>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
5. 输入框过滤空格
输入框使用 .trim 修饰符或手动 trim(),避免空格导致查询/提交异常。
<!-- 方式一:v-model.trim -->
<el-input v-model.trim="queryParams.keyword" placeholder="请输入关键字" />
<!-- 方式二:@blur 时手动 trim -->
<el-input v-model="formData.name" @blur="formData.name = formData.name.trim()" />
6. 支持回车触发查询
筛选表单支持按 Enter 键直接触发查询,减少鼠标操作。
<el-form @submit.prevent="handleQuery">
<el-input
v-model.trim="queryParams.keyword"
placeholder="请输入关键字"
@keyup.enter="handleQuery"
clearable
/>
</el-form>
16. 数字输入框限制
数字输入框限制输入类型,禁止输入非法字符。
<el-input
v-model="formData.amount"
placeholder="请输入金额"
@input="formData.amount = formData.amount.replace(/[^\d.]/g, '')"
/>
<!-- 或使用 el-input-number -->
<el-input-number v-model="formData.quantity" :min="0" :max="99999" :precision="0" />
17. 日期选择范围限制
日期选择器通过 disabled-date 限制可选范围,避免选择无效日期。
<el-date-picker
v-model="formData.date"
type="date"
placeholder="请选择日期"
:disabled-date="disabledDate"
/>
function disabledDate(time: Date) {
return time.getTime() > Date.now()
}
五、加载与状态反馈
7. Table 加载 Loading 状态
数据加载时必须显示 loading,避免空白页面让用户困惑。
<el-table :data="tableData" :height="tableHeight" v-loading="tableLoading">
<!-- columns -->
</el-table>
const tableLoading = ref(false)
async function getList() {
tableLoading.value = true
try {
const res = await fetchListApi(queryParams)
tableData.value = res.data.rows
total.value = res.data.total
} finally {
tableLoading.value = false
}
}
8. 列表空状态提示
列表无数据时显示空状态组件,区分"加载中"与"确实没有数据"。
<el-table :data="tableData" :height="tableHeight" v-loading="tableLoading">
<!-- columns -->
<template #empty>
<el-empty description="暂无数据" />
</template>
</el-table>
12. 操作成功消息反馈
增删改操作成功后统一使用 ElMessage.success 提示,让用户明确知道操作已完成。
ElMessage.success('新增成功')
ElMessage.success('修改成功')
ElMessage.success('删除成功')
六、危险操作保护
13. 删除等危险操作二次确认
删除、重置等不可逆操作必须使用 ElMessageBox.confirm 二次确认。
async function handleDelete(row: RowType) {
await ElMessageBox.confirm(
`确认删除「${row.name}」吗?删除后将无法恢复`,
'警告',
{ type: 'warning' }
)
await deleteApi(row.id)
ElMessage.success('删除成功')
getList()
}
七、分页与批量操作
14. 分页状态保持
编辑/删除后保持当前页码;新增后跳转第一页;删除当前页最后一条时自动回退上一页。
function afterEdit() {
getList() // 保持当前 queryParams.pageNum
}
function afterAdd() {
queryParams.pageNum = 1
getList()
}
function afterDelete() {
if (tableData.value.length === 1 && queryParams.pageNum > 1) {
queryParams.pageNum--
}
getList()
}
20. 批量操作前校验选中状态
批量操作前必须校验是否已选中数据,未选中时给出提示。
function handleBatchDelete() {
if (selectedRows.value.length === 0) {
ElMessage.warning('请至少选择一条数据')
return
}
ElMessageBox.confirm(
`确认删除选中的 ${selectedRows.value.length} 条数据吗?`,
'警告',
{ type: 'warning' }
).then(async () => {
const ids = selectedRows.value.map(row => row.id)
await batchDeleteApi(ids)
ElMessage.success('批量删除成功')
getList()
}).catch(() => {})
}
速查清单
| # | 规范 | 关键配置 / API |
|---|---|---|
| 1 | 列表一屏显示 | :height="tableHeight" 动态计算 |
| 2 | 弹窗禁止遮罩关闭 | :close-on-click-modal="false" |
| 3 | 流程操作防重复 | throttle / beforeClose 模式 |
| 4 | 下拉框可搜索 | filterable |
| 5 | 输入框去空格 | v-model.trim |
| 6 | 回车查询 | @keyup.enter |
| 7 | 表格 Loading | v-loading |
| 8 | 空状态提示 | <el-empty> |
| 9 | 提交前校验 | formRef.validate() |
| 10 | 按钮 Loading | :loading="submitLoading" |
| 11 | 关闭前确认 | :before-close |
| 12 | 成功消息 | ElMessage.success() |
| 13 | 删除二次确认 | ElMessageBox.confirm() |
| 14 | 分页保持 | 条件判断 pageNum |
| 15 | 表单重置 | formRef.resetFields() |
| 16 | 数字输入限制 | replace / el-input-number |
| 17 | 日期范围限制 | :disabled-date |
| 18 | 操作列固定 | fixed="right" |
| 19 | 长文本省略 | show-overflow-tooltip |
| 20 | 批量操作校验 | 选中数量判断 |