Editable 行内编辑
点击文本即变为输入框;Enter 提交、Esc 取消、blur 自动提交,支持同步 / 异步校验。
何时使用
- 表格 / 详情面板 / 卡片头里单字段就地修改(标题、备注、标签)。
- 与
CfInput的差异:Input 是表单字段,永远展示边框;Editable 平时只展示文本,鼠标 hover 才出现编辑提示。 - 不要替代整个表单:复杂修改请用
CfModal+CfForm。
基础用法
单行 / 多行 / 禁用 / 同步异步校验都已经内置。validate 返回 true 才会提交,返回字符串视作错误信息。
背景 视口
<script setup lang="ts">
import { ref } from 'vue';
import { CfEditable, CfText } from '@chufix-design/vue';
const name = ref('北京 #3 机房');
const description = ref('用于承载海外回源流量,QPS 上限 12000。');
const restricted = ref('[email protected]');
async function validateName(next: string): Promise<true | string> {
if (!next.trim()) return '名称不能为空';
if (next.length > 30) return '不超过 30 个字符';
return true;
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px; max-width: 480px;">
<div>
<CfText size="sm" variant="muted">单行可编辑(带校验)</CfText>
<div style="font-size: var(--t-18); font-weight: var(--w-medium);">
<CfEditable v-model="name" :validate="validateName" aria-label="机房名称" />
</div>
</div>
<div>
<CfText size="sm" variant="muted">多行(Ctrl/Cmd+Enter 提交,Esc 取消)</CfText>
<CfEditable v-model="description" multiline placeholder="点击添加描述..." aria-label="描述" />
</div>
<div>
<CfText size="sm" variant="muted">禁用态</CfText>
<CfEditable v-model="restricted" disabled aria-label="主账号" />
</div>
</div>
</template> <script setup>
import { ref } from 'vue';
import { CfEditable, CfText } from '@chufix-design/vue';
const name = ref('北京 #3 机房');
const description = ref('用于承载海外回源流量,QPS 上限 12000。');
const restricted = ref('[email protected]');
async function validateName(next): Promise<true | string> {
if (!next.trim()) return '名称不能为空';
if (next.length > 30) return '不超过 30 个字符';
return true;
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px; max-width: 480px;">
<div>
<CfText size="sm" variant="muted">单行可编辑(带校验)</CfText>
<div style="font-size: var(--t-18); font-weight: var(--w-medium);">
<CfEditable v-model="name" :validate="validateName" aria-label="机房名称" />
</div>
</div>
<div>
<CfText size="sm" variant="muted">多行(Ctrl/Cmd+Enter 提交,Esc 取消)</CfText>
<CfEditable v-model="description" multiline placeholder="点击添加描述..." aria-label="描述" />
</div>
<div>
<CfText size="sm" variant="muted">禁用态</CfText>
<CfEditable v-model="restricted" disabled aria-label="主账号" />
</div>
</div>
</template> import { useState } from 'react';
import { CfEditable, CfText } from '@chufix-design/react';
export default function Demo() {
const [name, setName] = useState('北京 #3 机房');
const [description, setDescription] = useState('用于承载海外回源流量,QPS 上限 12000。');
const [restricted, setRestricted] = useState('[email protected]');
async function validateName(next: string): Promise<true | string> {
if (!next.trim()) return '名称不能为空';
if (next.length > 30) return '不超过 30 个字符';
return true;
}
return (
<>
<div style={{ display: "flex", flexDirection: "column", gap: 16, maxWidth: 480 }}>
<div>
<CfText size="sm" variant="muted">单行可编辑(带校验)</CfText>
<div style={{ fontSize: "var(--t-18)", fontWeight: "var(--w-medium)" }}>
<CfEditable value={name} onChange={setName} validate={validateName} aria-label="机房名称" />
</div>
</div>
<div>
<CfText size="sm" variant="muted">多行(Ctrl/Cmd+Enter 提交,Esc 取消)</CfText>
<CfEditable value={description} onChange={setDescription} multiline placeholder="点击添加描述..." aria-label="描述" />
</div>
<div>
<CfText size="sm" variant="muted">禁用态</CfText>
<CfEditable value={restricted} onChange={setRestricted} disabled aria-label="主账号" />
</div>
</div>
</>
);
} import { useState } from 'react';
import { CfEditable, CfText } from '@chufix-design/react';
export default function Demo() {
const [name, setName] = useState('北京 #3 机房');
const [description, setDescription] = useState('用于承载海外回源流量,QPS 上限 12000。');
const [restricted, setRestricted] = useState('[email protected]');
async function validateName(next): Promise<true | string> {
if (!next.trim()) return '名称不能为空';
if (next.length > 30) return '不超过 30 个字符';
return true;
}
return (
<>
<div style={{ display: "flex", flexDirection: "column", gap: 16, maxWidth: 480 }}>
<div>
<CfText size="sm" variant="muted">单行可编辑(带校验)</CfText>
<div style={{ fontSize: "var(--t-18)", fontWeight: "var(--w-medium)" }}>
<CfEditable value={name} onChange={setName} validate={validateName} aria-label="机房名称" />
</div>
</div>
<div>
<CfText size="sm" variant="muted">多行(Ctrl/Cmd+Enter 提交,Esc 取消)</CfText>
<CfEditable value={description} onChange={setDescription} multiline placeholder="点击添加描述..." aria-label="描述" />
</div>
<div>
<CfText size="sm" variant="muted">禁用态</CfText>
<CfEditable value={restricted} onChange={setRestricted} disabled aria-label="主账号" />
</div>
</div>
</>
);
} API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue / value | string | — | Vue v-model;React 受控 value |
placeholder | string | — | 空值占位(斜体显示) |
multiline | boolean | false | 渲染为 <textarea> |
disabled | boolean | false | 完全只读 |
showHint | boolean | true | hover 时显示铅笔图标 |
commitOnEnter | boolean | true | 单行 Enter 提交;多行需 Ctrl/Cmd+Enter |
maxLength | number | — | 字符上限 |
size | 'sm' | 'md' | 'lg' | 'md' | |
validate | (next) => boolean | string | Promise<...> | — | 返回 true 才提交;字符串作为错误消息显示 |
ariaLabel | string | — | 透传到外层 role="button" |
Events
| Vue 事件 | React 回调 | 载荷 | 说明 |
|---|---|---|---|
update:modelValue | onChange | 新值 | 提交时触发 |
commit | onCommit | { value, previous } | 提交成功(值有变化) |
cancel | onCancel | — | Esc 撤销 |
edit-start | onEditStart | — | 进入编辑态 |
invalid | onInvalid | string | 校验失败时返回的错误消息 |
反馈与讨论
Editable 行内编辑 的讨论