一行实现ant-design-vue 表格合并&form动态生成合并表格

23 阅读3分钟

github项目地址 ps:可以的话给个start 嘿嘿嘿

注: 项目中Eitem属性只是为了方便查看,实际使用中由于dataIndex值不固定 建议使用string代替

两个简单合并的实现原理见此链接

form表单及表格的合并实现原理见此链接

1、简单合并--推荐同步数据使用

优点:不需要我们去处理column

缺点:是若数据是异步加载,column需要设置为ref,相比于下面的法二更加损耗性能

stopKey用于节省性能,如案例中,确定合并位置只需要到【运行内存】即可,后续的列不用合并,则可以将stopKey值设置为EItem.attr3(运行内存的dataIndex为EItem.attr3)

    <template>
      <PageLayout :navs="['合并表格', '简单合并']" title="简单合并">
        <a-table bordered :columns="resultColumns" :dataSource="list"></a-table>
      </PageLayout>
    </template>
    ​
    <script setup lang="ts">
    import { columns, list } from './config'
    import { EItem } from './config'
    import { getMergeColumn } from '@/utils/tools/easy-table-merge'
    const resultColumns = getMergeColumn(columns, list, { stopKey: EItem.attr3 })
    </script>
    ​
    <style scoped></style>
    ​

效果如下

image.png

2、简单合并--推荐异步数据使用

优点: columns只需要一次设置,不许要作为动态传入

缺点:需要手动设置customCell

这个在上面的基础上做了改进,可以选择哪些列需要合并单元格,在开始时以数组的方式传入(注意是要连续列的dataIndex)


    <template>
      <PageLayout :navs="['合并表格', '合并表格(静态列)']" title="合并表格(静态列)">
        <a-table bordered :columns="staticColumns" :dataSource="list"></a-table>
      </PageLayout>
    </template>
    ​
    <script setup lang="ts">
    import { addSpansValueInList } from '@/utils/tools/static-table-merge'
    import { list, staticColumns } from './config'
    import { EItem } from './config'
    addSpansValueInList([EItem.scheme, EItem.attr1, EItem.attr2, EItem.attr3], list)
    </script>
    

    export const staticColumns: TableColumnType[] = [
      {
        title: '套餐',
        dataIndex: EItem.scheme,
        width: 120,
        customCell: setCustomCell('scheme'),
      },
      {
        title: '内存',
        dataIndex: EItem.attr1,
        width: 120,
        customCell: setCustomCell('attr1'),
      },
      {
        title: '颜色',
        dataIndex: EItem.attr2,
        width: 120,
        customCell: setCustomCell('attr2'),
      },
      {
        title: '运行内存',
        dataIndex: EItem.attr3,
        width: 120,
      },
      {
        title: '进价',
        dataIndex: 'price',
        width: 120,
      },
      {
        title: '售价',
        dataIndex: 'price2',
        width: 120,
      },
    ]

效果与法一相同

3、form合并表格

效果: recording.gif

使用如下,具体的作用和方法都写在注释中,代码下方说一些特殊的配置

    <template>
      <PageLayout :navs="['合并表格', '用户操作']" title="用户操作">
        <a-form :model="form">
          <a-row :gutter="8">
            <a-col v-bind="spans" v-for="item in formGroup" :key="item.key">
              <a-form-item v-model:value="form[item.key]" :label="item.label">
                <a-select
                  mode="multiple"
                  v-model:value="form[item.key]"
                  :options="selectOptions[item.key]"
                ></a-select>
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
        <a-table
          :pagination="false"
          bordered
          :columns="resultColumns"
          :dataSource="resultList"
        >
          <template #bodyCell="{ column, record }">
            <template v-if="column.dataIndex === 'price'">
              <a-input v-model:value="record.price"></a-input>
            </template>
          </template>
        </a-table>
      </PageLayout>
    </template>
    ​
    <script setup lang="ts">
    import {
      columnsWithForm as columns,
      selectOptions,
      formGroup,
      spans,
    } from './config'
    import { userMergeByForm } from '@/composable/table/user-merge-by-form'
    ​
    // 通过异步方式获取选项配置和默认选中值
    const getSelectOptionApi = () => {
      return Promise.resolve({
        selectConfig: selectOptions,
        // 下面的填入值可以没有
        initForm: {
          attr1: [4, 5],
          attr3: [7, 9],
        },
      })
    }
    const { loadSelectOption, resultColumns, resultList, form } = userMergeByForm({
      // 模拟从后端动态获取表单选项和表单默认值
      getSelectOptionApi,
      // 要渲染的列
      fixColumns: columns,
      // 固定值,可直接设置或通过函数返回值获取
      fixColumnsConfig: {
        price: (record: any) => {
          if (record.attr1 === 4) {
            return 16
          }
          return 18
        },
        price2: 20,
      },
      // 要渲染的表单数组
      formGroup,
    })
    loadSelectOption()
    console.log(resultList)
    </script>
    ​

只说一些比较特殊的


`fixColumnsConfig`

    {
          ...
       fixColumnsConfig: {
        price: (record: any) => {
          if (record.attr1 === 4) {
            return 16
          }
          return 18
        },
        price2: 20,
      }
    }

如上配置表示

对于price1 ,若行数据中attr1(即内存)选中值对于的value为4则默认设置值16,否则设置值为18,效果如下图

setSelectOptionssetInitForm

我们期待后端在异步返回数据时格式如下

    {
        selectConfig: selectOptions,
        initForm: {
          attr1: [4, 5],
          attr3: [7, 9],
        },
     }

但当他返回格式不是我们想要的 则可以利用上述两函数进行取值,从而获取我们想要的数据

如:

后端返回

    const data = {
      meta: {
        selectConfig: {
          scheme: [
            { label: '套餐一', value: 11 },
            { label: '套餐二', value: 12 },
          ],
          attr1: [
            { label: '32G', value: 4 },
            { label: '64G', value: 5 },
            { label: '128G', value: 6 },
          ],
          attr2: [
            { label: '红色', value: 1 },
            { label: '黄色', value: 2 },
            { label: '绿色', value: 3 },
          ],
          attr3: [
            { label: '32G', value: 7 },
            { label: '64G', value: 8 },
            { label: '128G', value: 9 },
          ],
        },
      },
      other: {
        initForm: {
          attr1: [4, 5],
          attr3: [7, 9],
        },
      },
    }

我们可以使用如下

其中res就是接口的返回值

    const { loadSelectOption, resultColumns, resultList, form }=userMergeByForm({
      ....
      setInitForm:(res)=>res.meta.other.initForm,
      setSelectOptions: (res) => res.meta.selectOptions,
    })