前言:el-easytable是基于vue3jsx element ui参照antd design pro实现的复合表格和可编辑表格,里面的属性和用法基本一致,但是由于vue 的数据是双向绑定的所以可编辑表格也会有所不同,好的意见评论区留言。
editTable组件api基本和protable组件一摸一样的,重复的这里不再介绍
组件同时支持vue3 jsx 和 template,个人建议复杂表格最好使用jsx用法,简单,灵活,易扩展;因为受语法限制template代码量往往更多,处理更复杂
一、使用
1.安装
npm i el-easytable -S
2.引用
import { ProTable,EditTable } from "el-easytable"
import "el-easytable/dist/style.css";
二、EditTable 用法示例
1.基础用法
(1)单行编辑表格
template语法
<template>
<EditTable
headerTitle="可编辑表格"
:search="false"
:singleEdit="true"//单行编辑
:columns="columns"
v-model:form="state.form.data"//通过传form双向绑定表单值
/>
</template>
<script setup lang="ts" name="SingleRowEditDemo">
import { reactive, onMounted } from "vue";
import {EditTable} from "el-easytable";
import {data} from "../json.js";
const columns = [
{label: "姓名", prop: "name", required: true},
{
label: "性别",
prop: "gender",
valueType: "select",
// multiple: true,
// remote: true,
// valueEnum: () => [//静态
// {label: "男", value: 1, status: 'success'},
// {label: "女", value: 2, status: 'error'}
// ]
remoteMethod: ()=>[//远程获取选项数据,可搜索同原生el-select remote-method
{label: "男", value: 1, status: 'success'},
{label: "女", value: 2, status: 'error'}
]
},
{
label: "年龄",
prop: "age",
valueType: "number",
max: 150,
min: 1,
precision: 0,
summary: true,
// defaultValue: 12
},
{
label: "出生年月",
prop: "date",
valueType: "date",
disabled: (_, row) => {
return row.age === 27;
},
edit:false
},
{
label: "籍贯",
prop: "areaSelect",
valueType: 'areaSelect',
address: 'address',
required: true,
},
{
label: "个人介绍",
prop: "textarea",
valueType: "textarea"
},
{
label: "操作",
valueType: "action",
width: 140,
action: ["edit", "remove", "add"]
}
];
const state = reactive({
form: {
data: []
}
});
onMounted(async () => {
state.form.data = data;
});
</script>
(2) 整表可编辑
这是个嵌套表格用例
jsx语法
<script lang="jsx" name="editTableJsx">
import {defineComponent, reactive, ref} from "vue";
import {EditTable} from "el-easytable";
import {ElMessage} from "element-plus";
import {data} from "../json.js";
const columns = [
{label: "姓名", prop: "name", required: true},
{
label: "性别",
prop: "gender",
valueType: "select",
// multiple: true,
valueEnum: () => [
{label: "男", value: 1, status: 'success'},
{label: "女", value: 2, status: 'error'}
]
},
{
label: "年龄",
prop: "age",
valueType: "numberString",
max: 150,
min: 1,
precision: 0,
summary: true,
initValue: 12
},
{
label: "出生年月",
prop: "date",
valueType: "date",
disabled: (_, row) => {
return row.age === 27;
}
},
{
label: "籍贯",
prop: "diy",
valueType: 'areaSelect',
address: 'address'
},
{
label: "个人介绍",
prop: "textarea",
valueType: "textarea"
},
{
label: "自定义",
prop: "diy",
render: (_, row, index) => <div>
<p>姓名:{row?.name}</p>
<p>年龄:{row?.age}</p>
<p>index:{index}</p>
</div>
},
{
label: "操作",
valueType: "action",
action: ["remove", "add"]
}
];
export default defineComponent({
setup() {
const editRef = ref(null);
const childRef = ref([]);
const form = reactive({
data
});
const onSubmit = async () => {
const check = await editRef?.value?.onValid();
if (!check) {
ElMessage.warning("请完善表格必填(带*)项");
return;
}
for (let i = 0; i < form.data?.length; i++) {
const checks = await childRef.value[i]?.onValid?.();
if (!checks) {
ElMessage.warning("请完善嵌套表格必填(带*)项");
return;
}
}
ElMessage.success("操作成功");
};
return () => (
<>
<EditTable
headerTitle="编辑列表jsx"
ref={editRef}
v-model:form={form.data}
columns={columns}
summary={{
showSummary: true
}}
expand={({row, $index}) => {
const child = row?.child || [];
return row?.child?.length ? (
<EditTable
ref={el => el && (childRef.value[$index] = el)}
v-model:form={child}
columns={columns}
/>
) : null;
}}
/>
<div className="flex-pc">
<el-button type="primary" onClick={onSubmit}>
提交
</el-button>
</div>
</>
);
}
});
</script>
template语法
<template>
<EditTable
headerTitle="编辑列表"
ref="editRef"
v-model:form="state.form.data"
:columns="columns"
:summary="{
showSummary: true
}"
>
<template #expand="{ row, $index }">
<EditTable v-if="row.child && row.child.length"
:ref="el => el && (childRef[$index] = el)"
v-model:form="row.child"
:columns="columns"
/>
</template>
<template #empty>
<p>空空如也</p>
</template>
</EditTable>
<div class="flex-pc">
<el-button type="primary" @click="onSubmit">提交</el-button>
</div>
</template>
<script setup lang="ts" name="editTableDemo">
// @ts-nocheck
import {reactive, ref, onMounted} from "vue";
import {EditTable} from "el-easytable";
import {ElMessage} from "element-plus";
import {data} from "../json.js";
//columns配置项支持其valueType对应的原生el组件的任何属性
const columns = [
{label: "姓名", prop: "name", required: true},
{
label: "性别",
prop: "gender",
valueType: "select",
valueEnum: (_,row) => row?.genderList||[
{label: "男", value: 1, status: 'success'},
{label: "女", value: 2, status: 'error'}
]
},
{
label: "年龄",
prop: "age",
valueType: "number",
max: 150,//最大值
min:(_,row)=>row?.minAge|| 1,//最小值,当你需要用到当前行数据row,你可以在其callback中拿,当你使用的slot可在scope中取
precision: 2,//小数位
summary: true,//当前列汇总
},
{
label: "出生年月",
prop: "date",
valueType: "date",//当你需要时间区间,增加属性 type:"daterange" 支持原生el-date-picker 的所有属性
disabled: (_, row) => {
return row.age === 27;
}
},
{
label: "籍贯",
prop: "areaSelect",
valueType: 'areaSelect',
address: 'address'
},
{
label: "个人介绍",
prop: "textarea",
valueType: "textarea"
},
{
label: "自定义",
prop: "diy",
slot: {
default: "diy"
}
},
{
label: "操作",
valueType: "action",
action:(_,row)=>row.id?["remove", "add"]:["add"]//只有新增的行可删除
}
];
const editRef = ref(null);
const childRef = ref([]);
const state = reactive({
form: {
data,
summary: {}
}
});
onMounted(async () => {
state.form.data = data;
});
const onSubmit = async () => {
const check = await editRef?.value?.onValid();
if (!check) {
ElMessage.warning("请完善表格必填(带*)项");
return;
}
for (let i = 0; i < state.form.data?.length; i++) {
if (!childRef.value[i]) continue;
const checks = await childRef.value[i]?.onValid?.();
if (!checks) {
ElMessage.warning("请完善嵌套表格必填(带*)项");
return;
}
}
ElMessage.success("操作成功");
};
</script>
三、api
插槽
| 插槽名 | 描述 |
|---|---|
| toolBarRender | 表格上方按钮 |
| tableAlertRender | 表头汇总行 |
| expand | 表格每行的嵌套 |
| 自定义,需要与columns种的slot中对应 | 表格每列的插槽,具体参见 columns slot属性 |
- 自定义插槽用法-action
<template #action="{ row, action, $index }">
<el-link class="mr-10" type="primary" @click="action?.add?.(row)"
>复制
</el-link>
<el-link class="mr-10" type="error" @click="action?.remove?.($index)"
>删除
</el-link>
</template>
{
label: '操作',
valueType: 'action',
slot: {
default: 'action'//名字与 template中#后名字对应
}
}
属性
- EditTable支持所有
element plusTable中所有的属性 - 以下所列是基于其原有属性的扩展,除了拥有ProTable的全部属性外,EditTable独有的属性
| 属性名 | 默认值 | 类型 | 描述 | 用法 |
|---|---|---|---|---|
| form | {} | Object | 双向绑定v-model:form绑定的值 | 比如你再js中已经有了const state=reactive({form:{}});那么在组件属性中添加 v-model:form={state.form}实现表格值双向绑定 |
| canDelLast | false | Boolean | 是否可以删除最后一行,默认为false表示不可删除最后一行且当data数据为空时会默认设置为仅有一行各项为空的表格为 true表示可以删除最后一行直至为空,且data数据为空时表格为空显示'暂无数据' | canDelLast={true} |
| singleEdit | false | Boolean | 是否单行编辑表格 | singleEdit={true} |
| onEdit | false | Boolean | 点击单行编辑按钮事件 | onEdit={(item, row, index)=>{} |
| saveEdit | false | Boolean | 保存单行编辑按钮事件 | saveEdit={(item, row, index)=>{} |
| cancelEdit | false | Boolean | 取消单行编辑按钮事件 | cancelEdit={(item, row, index)=>{} |
request属性
<EditTabel
params={{type: query.type}}
v-model:form="state.form.data"
request={async (params) => state.form.data = await getUserList({...params, code: '001'})}
/>
rowSelection属性
<ProTabel
:rowSelection="{
type: 'radio',//默认多选,type=radio为单选
rowKey: 'age',//关键字段key
onSelectionChange:(selection)=>{},
selectable:(row, index)=>{},//selectable用于控制可筛选行的方法
}"
/>
columns属性
- columns支持
element plusTable中对应的所有的属性 - 以下所列是:除了拥有ProTable的全部columns属性外,EditTable独有的columns属性
| 属性名 | 类型 | 描述 | 用法 |
|---|---|---|---|
| onChange | Function | 单元格的change事件,3个参数,具体参见onChange属性 | onChange:(val,row,index) => {} |
| edit | Boolean|Function | 当前单元格是否是可编辑的表单,默认为true,为false时将直接渲染成对应值,同样3个参数 | edit:(item,row,index)=>row.status===1 |
| disabled | Boolean|Function | 当前单元格表单disabled值,同样3个参数 | disabled:(item,row,index)=>row.status===1 |
| max | Number|Function | valueType:'number'最大值,同样3个参数 | max:(item,row,index)=>row.maxNum |
| min | Number|Function | valueType:'number'最小值,同样3个参数 | min:(item,row,index)=>row.minNum |
| addParams | Object | valueType:'action'添加行时默认填充值, addParams: {feeList: [{}],goodsList: []} |
valueType属性
| 属性名 | 描述 |
|---|---|
| select | 自定义选择 |
| asyncSelect | 异步选择 ,具体参见对应插件 ,不可编辑时/proTable中内部使用span,若需回显请使用disalbed控制其是否可编辑 |
| enumsSelect | 静态枚举 ,具体参见对应插件 ,不可编辑时/proTable中内部使用span ,若需回显请使用disalbed控制其是否可编辑 |
| remoteSelect | 模糊查询 ,具体参见对应插件 ,不可编辑时/proTable中内部使用span ,若需回显请使用disalbed控制其是否可编辑 |
| date | 日期,完全支持element内部所有属性,不可编辑时/proTable中 内部调用?.format?.('YYYY-MM-DD'),默认处理为日期格式 |
| time | 时间,完全支持element内部所有属性,不可编辑时/proTable中 内部调用?.format?.('YYYY-MM-DD hh:mm:ss'),默认处理为时间格式 |
| timeRange | 时间区间,同时需要定义startTime:'开始字段名',endTime:'结束字段名' |
| upload | 文件,完全支持项目Upload组件内部所有属性,proTable中不可编辑仅展示 |
| input | 输入框 ,valueType属性的默认值,为此值时可不写 |
| number | 不可编辑时:为null展示'0.00'(小数位由precision属性设置)为非'-',可编辑时为:数值输入框 |
| index | 索引,不可编辑 |
| ellipsis | 仅不可编辑时/proTable中,超出单行宽度... 悬浮展示全部 |
| textarea | 文本域,不可编辑时/proTable中超出三行宽度... 悬浮展示全部 |
| action | 操作 |
| switch | 切换按钮仅editTable |
| numberString | 数字字符,可以0开头的数值 |
| currency | 仅proTable,默认两位消暑的数值 |
| areaSelect | 省市区级联选择 |
- valueType:'areaSelect'的具体用法
{
label: '起运地',
required:true,
prop:'startPlaceCodeList',//回显字段,值需要是[省code,市code,区code]类型
valueType: 'areaSelect',
address:'startAddress',//address:详细地址字段
onChange:(val, row) => {
//val返回一个对象,你可以任意处理提交给后端
/*
{
codes:[省code,市code,区code],
names:[省,市,区]
}
*/
const {codes, names} = val || {}
row.startPlace = names?.join?.('/')
row.startPlaceCode = codes?.join?.('/')
}
}
summary属性
{
summary:{
sumText:"总回款金额", // sumText:汇总合计文案,默认为'汇总
prop:"amount", // prop:参与汇总计算字段名,默认为当前项的'prop'值
precision:2,// precision:汇总计算总值保留小数位数,默认0位
}
}
render属性
{
render:(item, row, index) => {
return (
<el-button type="primary"
onClick={() => func({id: row.id})}
>激活</el-button>
)
}
}
// item:当前配置项对象
// row:当前行数据项
// index:当前列index
onChange属性
onChange:(val, row, index) => {
if (val === 1) {
row.num = 0
}
}
// val:当前表单改变的值
// row:当前行数据项
// index:当前列index
方法
- 以下所列是:除了拥有ProTable的全部columns属性外,EditTable独有的columns属性
| 方法名 | 接收参数类型 | 描述 | 用法 |
|---|---|---|---|
| onValid | 表格的校验方法 | refs.value?.onValid() |
具体用法
const refs = ref(null)
const submit = async () => {
//提交时必填校验
const check = refs.value?.onValid()
if (!check) {
ElMessage.warning('请完善表格必填信息')
return false
}
await api()
}
return () => (
<div>
<EditTable ref={refs}/>
<button onClick={submit}>提交</button>
</div>
)
四、vue3使用jsx需要做什么
这里基于vite打包工具介绍
1.安装支持jsx编译的插件
npm i @vitejs/plugin-vue-jsx -S
2.配置vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
export default defineConfig({
plugins: [vue(),vueJsx()],
})