Vue 3动态表单预览模式应采用readonly+样式隔离分层控制,保障数据可读可提交;配置驱动时统一注入readonly逻辑;保留tabindex与焦点以支持可访问性;服务端必须兜底校验权限。

在 Vue 3 动态表单中实现预览模式下的全局禁用,关键不是“一刀切加 disabled”,而是分层控制:既要视觉上明确不可编辑,又要保障数据可读、可提交、不破坏表单结构,同时避免因误用导致值丢失或校验异常。
用 readonly + 样式隔离替代全量 disabled
预览模式通常需展示已有内容(如详情页、审批流),此时若用 disabled,会导致表单字段不参与提交(FormData 或 v-model 绑定值被忽略),且部分组件(如 el-select)禁用后 placeholder 与文字颜色混同,难以区分“未填”和“已填但锁定”。推荐统一用 :readonly="isPreview",并配合 CSS 区分状态:
- 输入类组件(
<input>、<textarea></textarea>、el-input、a-input)设readonly,保留值提交能力 - 选择类组件(
el-select、el-date-picker、a-select)也设readonly(多数 UI 库支持该 prop);若不支持,则退回到:disabled="isPreview",但必须额外加隐藏域同步值:<input type="hidden" :name="field.key" :value="form[field.key]"> - 自定义样式强化语义:
.preview-mode .el-input.is-read-only { background: #fafafa; cursor: default; } .preview-mode .el-input.is-read-only input { color: #333; } .preview-mode .el-input.is-read-only ::placeholder { color: #bbb; }
动态字段配置中统一注入禁用逻辑
若使用配置驱动的动态表单(如通过 fields 数组生成),应在字段 schema 中预留控制开关,并在渲染时自动透传:
将静态 Vue 页面(index.vue)改造为动态页面(Custom.vue);稿源仅限 index.vue、其引用的 CSS 与资源路径,禁止参考仓库内其他文件。Invoke when user wants to transform a static Vue page into a dynamic data-driven page with Element UI components.
- 字段配置示例:
{ label: '邮箱', key: 'email', type: 'input', readonly: true },或更灵活地支持函数:readonly: () => isPreview.value - 模板中统一处理:
<component :is="getFieldComponent(field)" v-model="form[field.key]" :readonly="field.readonly ?? isPreview"></component> - 对 checkbox/radio 等布尔型控件,
readonly不生效,改用:disabled="isPreview"并确保其绑定值仍能正常读取
禁用交互但保留焦点与可访问性
预览模式下用户可能需要复制内容、聚焦查看长文本。直接禁用会剥夺 tabindex 和 focus 能力,影响可访问性(a11y)和基础体验:
立即学习“前端免费学习笔记(深入)”;
- 避免使用
pointer-events: none或移除tabindex,这会让屏幕阅读器无法识别控件 - 为所有预览态输入框显式设置
tabindex="0",保证键盘可聚焦 - 拦截关键事件但不阻断基础行为:
@keydown.prevent="isPreview && ['Enter', 'Space'].includes($event.code)",仅屏蔽触发操作的键,不影响方向键、复制(Ctrl+C)等
服务端兜底与权限一致性校验
前端禁用只是体验层优化,绝不能替代权限控制。预览模式往往对应「只读权限」,必须和服务端保持一致:
- 路由进入时,从接口拉取当前用户的资源权限(如
GET /api/employee/:id/permission),返回{ canEdit: false, canView: true },而非仅靠前端判断dialogStatus === 'view' - 提交前再次校验:
if (isPreview.value) { throw new Error('当前为只读模式,禁止提交'); }—— 防止用户绕过 UI 直接调用submitForm() - 后端接口必须独立校验权限,拒绝任何来自只读用户的写操作,无论请求是否携带伪造字段

















