You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1820 lines
32 KiB

---
description: cl-form 组件示例
globs: *.tsx, *.ts, *.vue
---
## 层级显示 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>children</el-tag>
<span>层级显示</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/children.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '层级显示',
items: [
{
label: '姓名',
prop: 'name',
component: {
name: 'el-input'
}
},
{
label: '年龄',
prop: 'age',
value: 18,
component: {
name: 'el-input-number'
}
},
// 基础信息
{
component: {
//【很重要】使用 cl-form-card 组件渲染,也可以使用自定义
name: 'cl-form-card',
props: {
// 标题
label: '基础信息',
// 是否展开,默认 true
expand: true
}
},
children: [
{
label: '账号',
prop: 'account',
component: {
name: 'el-input'
}
},
{
label: '密码',
prop: 'password',
component: {
name: 'el-input'
}
}
]
},
// 其他信息
{
component: {
name: 'cl-form-card',
props: {
label: '其他信息',
expand: false
}
},
children: [
{
label: '身份证',
prop: 'idcard',
component: {
name: 'el-input'
}
},
{
label: '学校',
prop: 'school',
component: {
name: 'el-input'
}
},
{
label: '专业',
prop: 'major',
component: {
name: 'el-input'
}
}
]
}
],
on: {
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 组件渲染 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>component</el-tag>
<span>组件渲染</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code
:files="[
'form/component/index.vue',
'form/component/select-labels.vue',
'form/component/select-status.vue',
'form/component/select-work.vue',
'form/component/select-work2.vue'
]"
/>
<!-- 自定义表单组件 -->
<cl-form ref="Form">
<!-- 年龄插槽 -->
<template #slot-age="{ scope }">
<!-- scope 为表单值 -->
<el-input-number v-model="scope.age" :min="18" :max="100"></el-input-number>
</template>
</cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
import { ElMessage } from 'element-plus';
import SelectWork from './select-work2.vue';
import SelectLabels from './select-labels.vue';
import SelectStatus from './select-status.vue';
const Form = useForm();
function open() {
Form.value?.open({
title: '组件配置',
items: [
{
label: '昵称',
prop: 'name',
// 组件配置方式1:标签名(方便,但是不建议组件全局注册)
value: '神仙',
component: {
// 必须是“全局注册”的组件名,如 element-plus 的 el-input、el-date-picker 等
name: 'el-input'
}
},
{
label: '手机号',
prop: 'phone',
value: '13255022000',
component: {
name: 'el-input',
// 自定义插槽
slots: {
prepend() {
return '+86';
}
}
}
},
{
label: '年龄',
prop: 'age',
// 组件配置方式2:插槽(万能,就是代码多写点)
value: 18,
component: {
// 必须是 "slot-" 开头
name: 'slot-age'
}
},
// -- start 组件配置方式3:组件实例(不想全局注册,但又想组件化)
{
label: '工作',
prop: 'work',
value: '设计',
component: {
// 双向绑定
vm: SelectWork
}
},
{
label: '标签',
prop: 'labels',
value: ['多金', '深情'],
component: {
// scope[prop]绑定
vm: SelectLabels
}
},
{
label: '状态',
prop: 'status',
value: 1,
component: {
// useForm 绑定
vm: SelectStatus
}
}
// -- end
],
on: {
submit(data, { close }) {
ElMessage.info(
`${data.name || '无名'}(${data.age || 18}岁)工作:${data.work || '无'}`
);
close();
}
}
});
}
</script>
```
## select-labels 示例
```vue
<template>
<!--【很重要】直接绑定表单值 scope[prop] -->
<!-- !符号,只是为了类型提示不错误 -->
<el-select v-model="scope[prop!]" multiple>
<el-option
v-for="(item, index) in list"
:key="index"
:label="item.label"
:value="item.label"
/>
</el-select>
</template>
<!--【很重要】必须要有name,避免注册后和其他冲突 -->
<script setup lang="ts">
defineOptions({
name: 'select-labels'
});
import { ref } from 'vue';
const props = defineProps({
scope: null, // 表单值
prop: String // 表单项配置的 prop
});
// 选项列表
const list = ref<{ label: string; value: string }[]>([
{
label: '帅气',
value: '帅气' // 测试直接使用label,真实情况可能是1,2,3,4或者id
},
{
label: '多金',
value: '多金'
},
{
label: '深情',
value: '深情'
}
]);
</script>
```
## select-status 示例
```vue
<template>
<!--【很重要】直接绑定status,或者使用 form[prop!] -->
<el-radio-group v-model="form.status">
<el-radio v-for="(item, index) in list" :key="index" :value="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</template>
<!--【很重要】必须要有name,避免注册后和其他冲突 -->
<script setup lang="ts">
defineOptions({
name: 'select-status'
});
import { useForm } from '@cool-vue/crud';
import { computed, ref } from 'vue';
const props = defineProps({
scope: null, // 表单值
prop: String // 表单项配置的 prop
});
// 使用 useForm,能直接获取到上级的表单实例,
// 比如操作表单的 Form.value?.submit、Form.value?.close等
// 获取表单值,Form.value?.form
const Form = useForm();
// 表单值,包一层不会太难受
const form = computed(() => Form.value?.form || {});
// 选项列表
const list = ref<{ label: string; value: number }[]>([
{
label: '很好',
value: 1
},
{
label: '不舒服',
value: 2
},
{
label: '要嘎了',
value: 3
}
]);
</script>
```
## select-work 示例
```vue
<template>
<el-select v-model="active" @change="onChange">
<el-option
v-for="(item, index) in list"
:key="index"
:label="item.label"
:value="item.label"
/>
</el-select>
</template>
<!-- 【很重要】必须要有name,避免注册后和其他冲突 -->
<script setup lang="ts">
defineOptions({
name: 'select-work'
});
import { ref, watch } from 'vue';
const props = defineProps({
modelValue: String
});
const emit = defineEmits(['update:modelValue', 'change']);
//【很重要】绑定值
// 这种方式虽然麻烦,但是可扩展性高,一些复杂的数据结构可以按这种方式绑定值
const active = ref();
// 选项列表
const list = ref<{ label: string; value: string }[]>([
{
label: '倒茶',
value: '倒茶' // 测试直接使用label,真实情况可能是1,2,3,4或者id
},
{
label: '设计',
value: '设计'
},
{
label: '开发',
value: '开发'
}
]);
//【很重要】更新绑定值,表单提交才能得到选择后的
function onChange(val: string) {
emit('update:modelValue', val);
emit('change', val);
}
//【很重要】使用监听的方式,避免表单打开数据是异步获取的情况
watch(
() => props.modelValue,
val => {
// 设置选中的值
active.value = val;
},
{
immediate: true
}
);
</script>
```
## select-work2 示例
```vue
<template>
<el-select v-model="active">
<el-option
v-for="(item, index) in list"
:key="index"
:label="item.label"
:value="item.label"
/>
</el-select>
</template>
<!-- 【很重要】必须要有name,避免注册后和其他冲突 -->
<script setup lang="ts">
defineOptions({
name: 'select-work2'
});
import { ref, useModel } from 'vue';
const props = defineProps({
modelValue: String
});
//【很重要】绑定值,使用 useModel 的方式双向绑定
const active = useModel(props, 'modelValue');
// 选项列表
const list = ref<{ label: string; value: string }[]>([
{
label: '倒茶',
value: '倒茶' // 测试直接使用label,真实情况可能是1,2,3,4或者id
},
{
label: '设计',
value: '设计'
},
{
label: '开发',
value: '开发'
}
]);
</script>
```
## 参数配置 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>config</el-tag>
<span>参数配置</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/config.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form">
<!-- 按钮插槽 -->
<template #slot-btns>
<el-button type="danger">按钮插槽</el-button>
</template>
</cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
import { ElMessage } from 'element-plus';
const Form = useForm();
function open() {
Form.value?.open({
title: '参数配置',
// 打开是否重置表单
isReset: false,
// 默认表单值
form: {
nickName: '神仙都没用'
},
// 表单配置
props: {
// 标签宽度
labelWidth: '120px',
// 标签位置
labelPosition: 'top'
},
// 窗口的高。配置后,在窗口内部滚动。默认整个页面滚动
height: '60vh',
// 窗口的宽,默认 50%
width: '60%',
// 窗口设置
dialog: {
// 是否隐藏头部
hideHeader: false,
// 顶部操作按钮,默认["fullscreen", "close"]
// fullscreen 全屏
// close 关闭
controls: ['close']
},
// 底部操作按钮
op: {
// 默认靠右布局
justify: 'flex-end',
// 保存按钮文字
saveButtonText: '提交',
// 关闭按钮文字
closeButtonText: '关闭',
// 是否隐藏
hidden: false,
// 按钮配置
buttons: [
// 自定义
{
label: '自定义按钮',
onClick() {
ElMessage.success('自定义按钮点击');
}
},
// close 关闭
'close',
// save 保存
'save',
// 插槽使用,配合 template,往上看 cl-form 组件
'slot-btns'
]
},
// 表单项配置
items: [
{
label: '昵称',
prop: 'nickName',
component: {
name: 'el-input'
}
}
],
// 事件
on: {
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 内嵌CRUD 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>crud</el-tag>
<span>内嵌CRUD</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/crud.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form">
<template #slot-crud>
<cl-crud ref="Crud" border>
<cl-row>
<!-- 刷新按钮 -->
<cl-refresh-btn />
<!-- 新增按钮 -->
<cl-add-btn />
<!-- 删除按钮 -->
<cl-multi-delete-btn />
<cl-flex1 />
<!-- 关键字搜索 -->
<cl-search-key placeholder="搜索姓名、手机号" />
</cl-row>
<cl-row>
<!-- 数据表格 -->
<cl-table ref="Table" />
</cl-row>
<cl-row>
<cl-flex1 />
<!-- 分页控件 -->
<cl-pagination />
</cl-row>
<!-- 新增、编辑 -->
<cl-upsert ref="Upsert" />
</cl-crud>
</template>
</cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useCrud, useForm, useTable, useUpsert } from '@cool-vue/crud';
// cl-upsert
const Upsert = useUpsert({
items: [
{
label: '姓名',
prop: 'name',
component: {
name: 'el-input'
}
},
{
label: '创建时间',
prop: 'createTime',
component: {
name: 'el-date-picker'
}
}
]
});
// cl-table
const Table = useTable({
autoHeight: false,
columns: [
{
type: 'selection'
},
{
label: '姓名',
prop: 'name',
minWidth: 140
},
{
label: '手机号',
prop: 'phone',
minWidth: 140
},
{
type: 'op'
}
]
});
// cl-crud
const Crud = useCrud(
{
service: 'test'
},
app => {
app.refresh({
size: 10
});
}
);
const Form = useForm();
function open() {
Form.value?.open({
title: '内嵌CRUD',
props: {
labelPosition: 'top'
},
dialog: {
height: '70vh',
width: '1000px'
},
items: [
{
label: '姓名',
prop: 'name',
component: {
name: 'el-input',
props: {
placeholder: '请填写姓名'
}
},
rules: {
required: true,
message: '姓名不能为空'
}
},
{
label: '内嵌 cl-crud',
component: {
name: 'slot-crud'
}
}
],
on: {
submit() {
Form.value?.close();
}
}
});
}
</script>
```
## 组件禁用 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>disabled</el-tag>
<span>组件禁用</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/disabled.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '组件禁用',
items: [
{
label: '账号',
prop: 'account',
component: {
name: 'el-input',
props: {
// 设置 boolean 值控制组件的禁用状态(前提是组件支持这个参数,element 的组件几乎都有)
disabled: true
}
}
},
{
label: '密码',
prop: 'password',
component: {
name: 'el-input'
}
}
],
on: {
open() {
// 通用 setProps 方法去设置 disabled, 1.5s后禁用
setTimeout(() => {
Form.value?.setProps('password', { disabled: true });
}, 1500);
},
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 组件事件 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>event</el-tag>
<span>组件事件</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/event.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
import { ElMessage } from 'element-plus';
const Form = useForm();
function open() {
Form.value?.open({
title: '组件事件',
items: [
{
label: '账号',
prop: 'account',
component: {
name: 'el-input',
props: {
// 组件内 emit 的用 on[name] 接收,如 onChange、onInput、onBlur 等
// 前提是组件内有触发事件
onBlur() {
ElMessage.info('账号检查中');
}
}
}
},
{
label: '是否实名',
prop: 'status',
value: 1,
component: {
name: 'el-radio-group',
options: [
{
label: '关闭',
value: 0
},
{
label: '开启',
value: 1
}
],
props: {
// 值改变事件
onChange(val: number) {
if (val == 1) {
// 显示表单项
Form.value?.showItem('idcard');
} else {
// 隐藏表单项
Form.value?.hideItem('idcard');
// 清空值
Form.value?.setForm('idcard', undefined);
}
}
}
}
},
{
label: '身份证',
prop: 'idcard',
component: {
name: 'el-input'
}
}
],
on: {
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 分组显示 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>group</el-tag>
<span>分组显示</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/group.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '分组显示',
items: [
{
//【很重要】必须为 tabs
type: 'tabs',
props: {
// 分组样式
type: 'card',
// 分组列表,必须是 { label, value } 的数组格式
labels: [
{
label: '基础信息', // 标题
value: 'base' // 唯一标识
},
{
label: '认证信息',
value: 'auth'
}
]
}
},
// 基础信息
{
group: 'base', // 标识
label: '账号',
prop: 'account',
required: true,
component: {
name: 'el-input'
}
},
{
group: 'base', // 标识
label: '密码',
prop: 'password',
required: true,
component: {
name: 'el-input'
}
},
// 其他信息 group = other
{
group: 'auth', // 标识
label: '身份证',
prop: 'idcard',
required: true,
component: {
name: 'el-input'
}
},
{
group: 'auth', // 标识
label: '学校',
prop: 'school',
component: {
name: 'el-input'
}
},
{
group: 'auth', // 标识
label: '专业',
prop: 'major',
component: {
name: 'el-input'
}
}
],
on: {
//【提示】当第一组验证通过后,会自动切换到下一组展示,直到全部通过才可提交
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 隐藏/显示 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>hidden</el-tag>
<span>隐藏/显示</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/hidden.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '隐藏/显示',
items: [
{
label: '状态',
prop: 'status',
value: 0,
component: {
name: 'el-radio-group',
options: [
{
label: '关闭',
value: 0
},
{
label: '开启',
value: 1
}
]
}
},
{
label: '账号',
prop: 'account',
component: {
name: 'el-input'
}
},
{
//【很重要】是否隐藏
hidden({ scope }) {
// scope 为表单值
// 返回一个 boolean 来控制当前表单项的隐藏/显示
return scope.status != 1;
},
label: '密码',
prop: 'password',
component: {
name: 'el-input'
}
}
],
on: {
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 布局 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>layout</el-tag>
<span>布局</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/layout.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '布局',
items: [
{
//【span】参考文档:https://element-plus.gitee.io/zh-CN/component/layout.html
// 使用 1/24 分栏,默认 24
span: 12,
label: '昵称',
prop: 'nickname',
component: {
name: 'el-input'
}
},
{
span: 12,
label: '手机号',
prop: 'phone',
component: {
name: 'el-input',
props: {
maxlength: 11
}
}
},
{
//【flex】使宽度不填充满
flex: false,
label: '标签',
prop: 'label',
component: {
name: 'el-input'
}
},
{
label: '状态',
prop: 'status',
value: 1,
component: {
name: 'el-radio-group',
options: [
{
label: '开启',
value: 1
},
{
label: '关闭',
value: 0
}
]
}
},
{
label: '备注',
prop: 'remark',
component: {
name: 'el-input',
props: {
type: 'textarea',
rows: 4
}
}
}
],
on: {
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 起步 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>open</el-tag>
<span>起步</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/open.vue']" />
<!-- 自定义表单组件 -->
<!--【很重要】ref 一定要对应 useForm 定义的值 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="tsx">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '起步',
items: [
{
label: '昵称',
// 绑定值的标识,表单提交及回显会自动根据 prop 获取对应的值
prop: 'nickname',
// 组件绑定
component: {
// 必须是“全局注册”的组件名,如 element-plus 的 el-input、el-date-picker 等
name: 'el-input',
// 绑定的组件参数配置,如 clearable、placeholder 等
// 组件内 emit 的用 on[name] 接收,如 onChange、onInput、onBlur 等
props: {
placeholder: '请输入昵称',
clearable: true,
onChange(value: string) {}
}
}
},
{
prop: 'age',
component: {
name: 'el-input-number'
},
// 默认值,第一次打开有效
value: 18
}
],
on: {
// 打开时触发
open() {
console.log(Form.value?.validateField);
},
// 关闭时触发。当配置该方法时,关闭事件会被阻断,使用 done() 关闭窗口
close(action, done) {
// action 为关闭窗口的触发动作 "save" | "close"
// done 关闭事件
done();
},
// 提交时触发
submit(data, { done, close }) {
// data 为表单值
// done 关闭加载事件、但不关闭窗口
// close 关闭窗口
close();
}
}
});
}
</script>
```
## 选项框配置 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>options</el-tag>
<span>选项框配置</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/options.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
import { computed, reactive } from 'vue';
const Form = useForm();
// 觉得麻烦就 any,如 { user: [] as any[] }
const options = reactive<{ [key: string]: { label: string; value: any }[] }>({
user: []
});
function open() {
Form.value?.open({
title: '选项框配置',
items: [
{
label: '下拉框',
prop: 'select',
component: {
name: 'el-select',
props: {
clearable: true // 可清除
},
options: [
{
label: 'javascript',
value: 1
},
{
label: 'vue',
value: 2
},
{
label: 'html',
value: 3
},
{
label: 'css',
value: 4
}
]
}
},
{
label: '单选框',
prop: 'radio',
value: 1,
component: {
name: 'el-radio-group',
options: [
{
label: '手机',
value: 1
},
{
label: '电脑',
value: 2
},
{
label: '电视',
value: 3
}
]
}
},
{
label: '多选框',
prop: 'checkbox',
value: [2, 3],
component: {
name: 'el-checkbox-group',
options: [
{
label: '咖啡',
value: 1
},
{
label: '汉堡',
value: 2
},
{
label: '炸鸡',
value: 3
},
{
label: '奶茶',
value: 4
}
]
}
},
{
label: '动态配置1',
prop: 'd1',
component: {
name: 'el-select',
// 动态设置方法1,在 on.open 事件配置 options
options: []
}
},
{
label: '动态配置2',
prop: 'd2',
component: {
name: 'el-select',
// 动态设置方法2,使用 computed 更新 options
options: computed(() => options.user)
}
}
],
on: {
open() {
// 模拟 1.5s 后取的数据
setTimeout(() => {
// 动态设置方法1,使用 setOptions 方法设置
// d1 为 prop 值
Form.value?.setOptions('d1', [
{
label: '😊',
value: 1
},
{
label: '😭',
value: 2
},
{
label: '😘',
value: 3
}
]);
// 动态设置方法2,直接设置 options.user,由 computed 更新
options.user = [
{
label: '💰',
value: 1
},
{
label: '🚗',
value: 2
}
];
}, 1500);
},
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 插件的使用 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>plugin</el-tag>
<span>插件的使用</span>
</div>
<div class="c">
<el-button @click="open('manager')">管理者</el-button>
<el-button @click="open('user')">用户</el-button>
<demo-code :files="['form/plugin/index.vue', 'form/plugin/role.ts']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
import { setRole } from './role';
const Form = useForm();
function open(role: string) {
Form.value?.open(
{
title: '插件的使用',
items: [
{
label: '姓名',
prop: 'name',
required: true,
component: {
name: 'el-input'
}
},
{
// 自定义参数 role,匹配插件传入的角色
role: 'user',
label: '面试职位',
prop: 'work',
value: 1,
component: {
name: 'el-radio-group',
options: [
{
label: '前端开发',
value: 1
},
{
label: '后端开发',
value: 2
},
{
label: 'UI设计',
value: 3
}
]
}
},
{
role: 'user',
label: '期望薪资',
prop: 'salary',
value: 5000,
component: {
name: 'el-input-number',
props: {
min: 2000,
max: 100000
}
}
},
{
role: 'manager',
label: '入职时间',
prop: 'date',
component: {
name: 'el-date-picker'
}
},
{
role: 'manager',
label: '负责人',
prop: 'head',
component: {
name: 'el-input'
}
}
],
on: {
submit(data, { done, close }) {
close();
}
}
},
[
// 自定义插件,角色权限控制
setRole(role)
]
);
}
</script>
```
## 必填项配置 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>required</el-tag>
<span>必填项配置</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/required.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form"></cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
const Form = useForm();
function open() {
Form.value?.open({
title: '必填项配置',
items: [
{
label: '昵称',
prop: 'nickname',
component: {
name: 'el-input'
},
// 是否必填,默认判断绑定值是否空
required: true
},
{
label: '手机号',
prop: 'phone',
component: {
name: 'el-input',
props: {
maxlength: 11
}
},
// 自定义规则
// 基础用法可参考:https://element-plus.gitee.io/zh-CN/component/form.html
// 高级用法可参考:https://github.com/yiminghe/async-validator
rules: [
{
required: true,
validator: (rule, value, callback) => {
if (value === '') {
callback(new Error('手机号不能为空'));
} else if (!/^1[3456789]\d{9}$/.test(value)) {
callback(new Error('手机号格式错误'));
} else {
callback();
}
}
}
]
}
],
on: {
submit(data, { close }) {
close();
}
}
});
}
</script>
```
## 添加/删除表单项 示例
```vue
<template>
<div class="scope">
<div class="h">
<el-tag size="small" effect="dark" disable-transitions>rules</el-tag>
<span>添加/删除表单项</span>
</div>
<div class="c">
<el-button @click="open">预览</el-button>
<demo-code :files="['form/rules.vue']" />
<!-- 自定义表单组件 -->
<cl-form ref="Form">
<template #slot-cert="{ scope }">
<div class="cert">
<!--【很重要】prop、rules 配置格式如下 -->
<el-form-item
v-for="(item, index) in scope.cert"
:key="index"
:label="`证书${index + 1}`"
:prop="`cert.${index}.label`"
:rules="{
message: `请填写证书${index + 1}`,
required: true
}"
>
<div class="row">
<!-- 输入框 -->
<el-input v-model="item.label" placeholder="请填写证书"></el-input>
<!-- 删除行 -->
<el-icon @click="rowDel(index)">
<delete />
</el-icon>
</div>
</el-form-item>
<!-- 添加行 -->
<el-row type="flex" justify="end">
<el-button @click="rowAdd()">添加证书</el-button>
</el-row>
</div>
</template>
</cl-form>
</div>
<div class="f">
<span class="date">2024-01-01</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useForm } from '@cool-vue/crud';
import { Delete } from '@element-plus/icons-vue';
const Form = useForm();
function open() {
Form.value?.open({
title: '添加/删除表单项',
items: [
{
label: '昵称',
prop: 'nickname',
component: {
name: 'el-input'
},
required: true
},
{
prop: 'cert',
//【很重要】默认数据格式,以实际业务为主。
value: [
{
label: ''
}
],
component: {
name: 'slot-cert'
}
}
],
on: {
submit(data, { close }) {
close();
}
}
});
}
function rowAdd() {
Form.value?.form.cert.push({
label: ''
});
}
function rowDel(index: number) {
Form.value?.form.cert.splice(index, 1);
}
</script>
<style lang="scss" scoped>
.cert {
.row {
display: flex;
align-items: center;
.el-input {
flex: 1;
margin-right: 10px;
}
.el-icon {
cursor: pointer;
&:hover {
color: red;
}
}
}
}
</style>
```