element plus表格嵌套表单、可增减

表格内的单元格是可编辑的。

点击增加增加一条数据,点击删除删掉本条数据。

基本原理:

 <el-form ref="FormRef" :model="tableDataGroup" >
    <el-table :data="tableDataGroup.tableData">

         <template
            v-for="(item, colIndex) in tableSchema.tableColum"
            :key="colIndex"
          >
            <el-table-column
              :label="item.label"
              :width="item.width ? item.width : ''"
            >
                <el-form-item

    ...

表单是表格的父级。

数据格式说明:

const tableDataGroup = reactive({
  tableData: [
    {
      id: '1',
      name: 'ces1',
    },
    {
      id: '2',
      name: 'ces1',
    }
  ]
});

tableDataGroup是表单绑定的数据,tableDataGroup.tableData是表格绑定的数据,每一个数据项表示表格的每一行。

tableSchema.tableColum是表头,表头并不是一项一项地写,仍是采用数据渲染。之所以嵌套是因为虽然tableColumn是主要数据,但还会在tableSchema里增加许多表格整体的配置,比如需不需要操作栏,需不需要单选/多选栏等。

tableColum: [
    {
      label: '编号',
      prop: 'id',
      type: 'input',
      width: '50px',
      disabled: true
    },
    {
      label: '开始时间',
      prop: 'size',
      type: 'datetime'
    },

    ......

(这里不需要校验规则,所以不考虑那种复杂的情况,如果需要校验,那么CSDN

表头tableSchema.tableColum里写了几个字段,就会渲染几列,

表单根据scope渲染数据,可以理解为表格的每一行,对应每一个子表单(tableDataGroup是所有子表单的父级)。

    <el-table-column
      v-if="item.type"
      :label="item.label"
      :width="item.width ? item.width : ''"
       >
       <template #default="scope">
         <el-form-item>
            <FormItem :formData="scope.row" :data="item" :editable="true" />
         </el-form-item>
       </template>
    </el-table-column>

操作列的表头和单元格都采用插槽的形式,在父组件中写的增加按钮和删除按钮,分别对应tableDataGroup.tableData里每一项的增加和删除。

插槽,或者说具名插槽,就不多说了。

父组件中:

<el-button @click="dataListAdd(rowData)">增加</el-button>
...

function dataListAdd(data) {
  tableDataGroup.tableData.push({ id: '', name: '增加一条' });
}
...
<template #tableAction="{ rowData, index }">
   <el-button
      class="baq-button warn"
      @click="dataListDelet(rowData, index)"
      >删除</el-button
>
...

function dataListDelet(data, index) {
  tableDataGroup.tableData.splice(index, 1);
}
...

子组件中:

        <el-table-column v-else-if="item.label === '操作'" :width="100">
          <template #header="scope">
            <slot name="tableHeader" :rowData="scope.row"></slot>
          </template>

          <template #default="{ row, $index }">
            <slot name="tableAction" :rowData="row" :index="$index"></slot>
          </template>
        </el-table-column>


下面是部分代码:

MyTable.vue

<template>
  <el-form ref="FormRef" :model="tableDataGroup" :inline="true">
    <el-table
      :header-cell-style="{ 'text-align': 'center' }"
      border
      :cell-style="{ borderColor: '#3b90d0', 'text-align': 'center' }"
      :data="tableDataGroup.tableData"
    >
      <template
        v-for="(item, colIndex) in tableSchema.tableColum"
        :key="colIndex"
      >
        <el-table-column
          v-if="item.type"
          :label="item.label"
          :width="item.width ? item.width : ''"
        >
          <template #default="scope">
            <el-form-item>
              <FormItem :formData="scope.row" :data="item" :editable="true" />
            </el-form-item>
          </template>
        </el-table-column>
        <el-table-column v-else-if="item.label === '操作'" :width="100">
          <template #header="scope">
            <slot name="tableHeader" :rowData="scope.row"></slot>
          </template>

          <template #default="{ row, $index }">
            <slot name="tableAction" :rowData="row" :index="$index"></slot>
          </template>
        </el-table-column>
      </template>
    </el-table>
  </el-form>

  <div class="page-style">
    <el-pagination
      v-model:current-page="pageNum"
      v-model:page-size="pageSize"
      :page-sizes="[10, 20, 50, 100]"
      layout="total, sizes, prev, pager, next, jumper"
      :total="props.pageTotal || 0"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>

<script setup>
import formItem from '@/components/BaqForm/FormItem';
const FormItem = formItem();
const props = defineProps({
  tableSchema: Object,
  tableDataGroup: Object,
  pageTotal: Number
});
const emits = defineEmits(['getFormData']);
const FormRef = ref();
const pageNum = ref(1);
const pageSize = ref(10);

const handleSizeChange = val => {
  console.log(`${val} items per page`);
  searchForm('search', val, pageNum.value);
};
const handleCurrentChange = val => {
  console.log(`current page: ${val}`);
  searchForm('search', pageSize.value, val);
};

// 查询/重置
async function searchForm(val, size, num) {
  emits('getFormData', {
    pageNum: num || pageNum.value,
    pageSize: size || pageSize.value
  });
}

// 表单提交
async function submitForm() {
  return props.tableDataGroup.tableData;
}

// 表单校验
async function validate() {
  if (!FormRef.value) return;
  const result = await FormRef.value.validate();
  return result;
}

defineExpose({ validate, submitForm });
</script>

父组件:

<MyTable
        ref="tableRef"
        :tableSchema="tableSchema"
        :tableDataGroup="tableDataGroup"
        :pageTotal="pageTotal"
      >
        <template #tableHeader="{ rowData }">
          <el-button
            class="baq-button"
            style="margin: 0"
            @click="dataListAdd(rowData)"
            >增加</el-button
          >
        </template>
        <template #tableAction="{ rowData, index }">
          <el-button
            class="baq-button warn"
            @click="dataListDelet(rowData, index)"
            >删除</el-button
          >
        </template>
 </MyTable>

数据:

const tableDataGroup = reactive({
  tableData: [
    {
      id: '1',
      name: 'ces1'
    },
    {
      id: '2',
      name: 'ces1'
    }
  ]
});



export const tableSchema = {
  tableColum: [
    {
      label: '编号',
      prop: 'id',
      type: 'input',
      width: '50px',
      clearable: '1',
      disabled: true
    },
    {
      label: '开始时间',
      prop: 'size',
      type: 'datetime'
    },
    {
      label: '结束时间',
      prop: 'type',
      type: 'datetime'
    },
    {
      label: '名称',
      prop: 'name',
      type: 'select',
      options: [
        {
          label: '111',
          value: '111'
        }
      ]
    },
    {
      label: '内容',
      prop: 'content',
      type: 'select',
      options: [
        {
          label: '111',
          value: '111'
        }
      ]
    },
    {
      label: '备注',
      prop: 'editTime',
      type: 'input'
    },
    {
      label: '操作',
      prop: 'action'
    }
  ]
};

FormItem.jsx

这是有参考的CSDN

import {
  ElCheckbox,
  ElCheckboxGroup,
  ElDatePicker,
  ElInput,
  ElInputNumber,
  ElOption,
  ElRadio,
  ElRadioGroup,
  ElSelect,
  ElTimePicker,
  ElTreeSelect
} from 'element-plus';
import { defineComponent } from 'vue';


// 普通显示
const Span = (form, data) => (
  <span>
    {form[data.prop]}
  </span>
);

// 输入框
const Input = (form, data) => (
  <div style={ 'display:flex; align-items:center;' }>
 <ElInput
    v-model={form[data.prop]}
    type={data.type}
    size="default"
    show-password={data.type == 'password'}
    clearable={data.clearable==='1'?false:true}
    disabled={data.disabled}
    placeholder={'请输入' + data.label}
    autosize={{
      minRows: 3,
      maxRows: 4
      }}
    style={ data.append? 'margin-right: 8px; width:100px':''}
    {...data.props}
  ></ElInput><span v-show={data.append?true:false} style={ 'color: #333; line-height:32px'}>{data.append}</span>
  </div>
);

// 数字输入框
const InputNumber = (form, data) => (
  <ElInputNumber
    size="default"
    v-model={form[data.prop]}
    disabled={data.disabled}
    controls-position="right"
    {...data.props}
  />
);

const setLabelValue = (_item, { optionsKey }) => {
  return {
    label: optionsKey ? _item[optionsKey.label] : _item.label,
    value: optionsKey ? _item[optionsKey.value] : _item.value
  };
};
// 选择框
const Select = (form, data) => (
  <ElSelect
    size="default"
    v-model={form[data.prop]}
    filterable
    disabled={data.disabled}
    clearable
    placeholder={'请选择' + data.label}
    {...data.props}
  >
    {
      data.options?data.options.map((item) => {
      return <ElOption {...setLabelValue(item, data)} />;
      }):''
    }
  </ElSelect>
);

// 单选/区间日期
const Date = (form, data) => (
  <ElDatePicker
    size="default"
    v-model={form[data.prop]}
    type={data.type}
    value-format={data.valueFormat}
    format={data.format}
    disabled={data.disabled}
    range-separator="-"
    style={ data.width?'width:'+ data.width:'width:200px'}
    start-placeholder={data.startPlaceholder}
    end-placeholder={data.endPlaceholder}
    placeholder={'请选择' + data.label}
    startPlaceholder={data.type === 'daterange' ? '开始时间' : ''}
    endPlaceholder={data.type==='daterange'?'结束时间':'' }
    {...data.props}
  />
);

// 单选/区间时间
const Time = (form, data) => (
  <ElTimePicker
    size="default"
    v-model={[form[data.prop]]}
    value-format={data.valueFormat}
    format={data.format}
    range-separator="至"
    disabled={data.disabled}
    start-placeholder={data.start}
    is-range={data.isRange}
    end-placeholder={data.end}
    {...data.props}
  />
);

// 单选
const Radio = (form, data) => (
  <ElRadioGroup disabled={data.disabled} v-model={form[data.prop]}>
    {data.radios?data.radios.map(
      (item) => {
        return (
          <ElRadio label={setLabelValue(item, data.prop).value}>
            {setLabelValue(item, data.prop).label}
          </ElRadio>
        );
      }
    ):''}
  </ElRadioGroup>
);

// 多选
const Checkbox = (form, data) => (
  <ElCheckboxGroup disabled={data.disabled} size="default" v-model={form[data.prop]}>
    {data.checkboxs.map(
      (item) => {
        return (
          <ElCheckbox label={setLabelValue(item, data.prop).value}>
            {setLabelValue(item, data.prop).label}
          </ElCheckbox>
        );
      }
    )}
  </ElCheckboxGroup>
);

const TreeSelect = (form, data) => (
  <ElTreeSelect data={data.treeList} v-model={form[data.prop]} props={data.props} check-strictly={data.checkStrictly} /> 
)


const setFormItem = (
  form,
  data,
  editable
) => {
  if (!form) return null;
  if (!editable) return Span(form, data);
  switch (data.type) {
    case 'input':
      return Input(form, data);
    case 'textarea':
      return Input(form, data);
    case 'password':
      return Input(form, data);
    case 'inputNumber':
      return InputNumber(form, data);
    case 'select':
      return Select(form, data);
    case 'treeSelect':
      return TreeSelect(form,data)
    case 'date':
    case 'daterange':
    case 'datetime':
      return Date(form, data);
    case 'time':
      return Time(form, data);
    case 'radio':
      return Radio(form, data);
    case 'checkbox':
      return Checkbox(form, data);
    default:
      return null;
  }
};

export default () =>
  defineComponent({
    props: {
      data: Object,
      formData: Object,
      editable: Boolean
    },
    setup(props) {
      return () =>
        props.data
          ? setFormItem(props.formData, props.data, props.editable)
          : null;
    }
  });

element表格是一种常见的用于展示和组织数据的形式,而嵌套表单则是在element表格中嵌入的一种特殊形式的表单嵌套表单是指在element表格的某一行或某一列中,以表单的形式进一步展示具体的数据或提供数据录入的功能。例如,在一个员工信息表格中,可以为每个员工提供一个嵌套表单,以展示或编辑他们的联系信息、薪资等详细数据。 使用element表格嵌套表单的好处包括: 1. 数据展示更加清晰:通过嵌套表单的方式,可以将详细的数据信息以表单的形式展示在表格的某一行或某一列中,使得数据的结构更加清晰,便于用户浏览和理解。 2. 方便数据编辑:通过嵌套表单,用户可以直接在表格中进行数据的编辑和更新,无需跳转到其他页面或打开弹窗,提高了数据的操作效率。 3. 紧凑的布局:嵌套表单可以将更多的数据信息以表单的形式收纳在表格中,不会占用额外的页面空间,使得整体布局更加紧凑,提升了页面的可用性和美观性。 4. 数据关联性强:通过嵌套表单,可以将不同表格中的相关数据进行关联,使得数据之间的联系更加明确和直观,方便用户进行跨表格的操作和分析。 总之,element表格嵌套表单是一种有效的数据展示和操作方式,可以提高用户对数据的理解和操作效率。它在各种管理系统、数据展示系统等场景中都有广泛的应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值