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
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>
|
|
|
|
```
|