使用antd的a-table在vue中实现表格表头纵排列

效果如图:

红框内是我们的表头,正常表格都是表头在上,我们这边实现了表头在左,动态数据在右

代码如下:

1,声明表格,使用框架自带的a-table,核心点在data和columns上

我们先来看一下正常使用的a-table:

           <a-table
            bordered // 展示外边框和列边框
            :columns="columns" // 自己定义的表格列的配置数组
            :data-source="publicData" // 后端返回的动态数据
            :scroll="{ x: 1500, y: '50vh' }" // 指定滚动区域的宽和高
            :pagination="false" // 分页器
            :rowKey="(record) => record.id" // 表格行 key 的取值
          >
          </a-table>

再来看一下表头在左的a-table

       <a-table
           bordered
           :columns="areaHeader"
           data-source="getValues()" // 数据数组,这里的数据数组是个方法,下面会讲
           :pagination="false"
           :rowKey="(record,index) => index"
           :showHeader="false" // 是否显示表头
         >
     </a-table>

会发现有两处改动,我们的data-source变成了一个方法,新增了一个shouHeader的API

2,设置表头columns:

//label是表头,props是对应的数据。这里换成你们自己的数据即可
const columns = [
  {
    label: "项目",
    props: "scheme_name",
  },
  { label: "单位最低基数", props: "unit_min"},
  {
    label: "单位最高基数",
    props: "unit_highest",
  },
  {
    label: "个人最低基数",
    props: "staff_min",
  },
  {
    label: "个人最高基数",
    props: "staff_highest",
  },
  {
    label: "单位收款方式",
    props: "unit_payment",
  },
  {
    label: "单位参保规则",
    props: "unit_insured_rule",
  },
  {
    label: "单位比例",
    props: "unit_proportion",
  },
  {
    label: "单位最低金额",
    props: "unit_minPrice",
  },
  {
    label: "单位最高金额",
    props: "unit_maxPrice",
  },
  {
    label: "单位补缴",
    props: "unit_supplementary",
  },
  {
    label: "个人收款方式",
    props: "staff_payment",
  },
  {
    label: "个人参保规则",
    props: "staff_insured_rule",
  },
  {
    label: "个人比例",
    props: "staff_proportion",
  },
  {
    label: "个人最低金额",
    props: "staff_minPrice",
  },
  {
    label: "个人最高金额",
    props: "staff_maxPrice",
  },
  {
    label: "个人补缴",
    props: "staff_supplementary",
  },
  {
    label: "最低合计",
    props: "minPrice",
  },
  {
    label: "最高合计",
    props: "maxPrice",
  },
  {
    label: "扣款日期",
    props: "deduction_date",
  }
];

3,绑定数据-js部分

        记得在data里声明一个areaHeader:[],// 转换表头

在methods中:

// 转换表头
        getHeaders () {
            let data = this.columns.reduce((pre, cur, index) => pre.concat({ 'dataIndex': `value${index}` }), [{ 'dataIndex': 'title' }])
            console.log('headers===>', data)
            this.areaHeader = data
        },
        // 转换绑定数据
        getValues () {
            let data = this.columns.map(item => {
                return this.formPro.settlement.reduce((pre, cur, index) => Object.assign(pre, { ['value' + index]: cur[item.props] }), { 'title': item.label })
            })
            console.log('value===>', data)
            return data
        },

最后在created里面执行一下this.getHeaders();就可以了

这里实现的思路是注册空数组,循环遍历成为一个新的数组,从打印的数据里可以看到,会生成一个新数组是我们转换过的,这就是为什么我们在上面data-source从后端返回的动态数据换成了我们getValues的方法。到这一步就可以实现表头纵排列了。如果还有什么疑问可以评论区留言讨论

antd组件a-table地址:Ant Design Vue

<think>我们需要使用Vue2和AntDesign Vue(通常称为antd-vue)来实现一个穿梭框(Transfer)组件,该组件通常用于在两个表格之间移动选项。AntDesign Vue的Transfer组件已经内置了这种功能,但题目要求使用两个表格实现,所以我们可以通过自定义渲染(`render`属性)来使用两个表格展示内容。注意:antd-vue的Transfer组件默认是列表形式,但我们可以自定义渲染为表格。这里我们使用Transfer组件,并通过自定义`render`来渲染表格。步骤:1.安装antd-vue(如果尚未安装):`npminstall ant-design-vue@1.7.8 --save`(Vue2对应的是1.x版本)2.在项目中引入antd-vue的Transfer、Table、Button等组件。由于要求使用两个表格,我们将使用Transfer组件的自定义渲染功能,将左右两边的列表渲染成表格。示例代码:注意:这里我们使用Vue2的语法。我们将实现一个简单的穿梭框,数据源包含key和标题,并且可以显示在左右两个表格中,通过按钮进行移动。代码结构:-使用a-transfer组件-自定义render属性,返回一个表格(a-table-定义数据源(mock数据)-定义目标键(targetKeys)用于存储右侧(目标)数据的key功能:-全选:表格头部的复选框可以全选当前列表-穿梭:通过中间的按钮移动选中的数据注意:Transfer组件本身已经处理了数据的移动,我们只需要提供自定义的渲染方式。由于Transfer组件要求数据源格式为:`[{ key, title}]`,但我们在表格中可能需要展示更多字段,因此我们可以将数据扩展,比如:`[{key,name,age,... }]`,然后在自定义渲染的表格中展示多个字段。实现-使用`scopedSlots`自定义渲染列表(在antd-vue1.x中,Transfer的`render`属性是一个函数,它接收一个参数(每一项数据),返回一个VNode。但为了渲染整个列表为表格,我们需要使用`list-style`和`render`属性,然而antd-vue的Transfer组件并没有直接支持整个列表渲染为表格。因此,我们可以通过自定义两个插槽的方式,但是antd-vue1.x的Transfer不支持插槽。所以,我们这里使用另一种方式:利用Transfer组件的`render`属性返回一个表格行(即每一项作为表格的一行),同时整个列表会渲染成一个表格。但是这样需要我们自己构建整个表格结构。实际上,Transfer组件的左右两个列表是分别渲染的,我们可以为每个列表渲染一个表格,每个表格只有tbody部分(没有表头),但这样不够美观。因此,我们可以自定义整个列表,包括表格表头。然而,Transfer组件的自定义渲染函数(`render`)是针对每一项的,所以我们需要在Transfer组件内部包裹一个表格,这样就需要在`render`函数中返回一个表格行(tr)。然后我们在Transfer组件外部包裹两个表格,但这样会破坏Transfer组件的结构。因此,我们采用另一种思路:不使用Transfer组件自带的列表样式,而是完全自定义左右两个面板(使用两个Table组件),然后通过中间的控制按钮来实现数据的移动。这样我们就可以完全控制两个表格的渲染,并且可以实现全选等功能。但是题目要求使用antd-vue,且要利用其Transfer组件,所以我们还是按照antd-vueTransfer组件的自定义渲染方式来实现。在antd-vue1.x中,Transfer组件提供了`render`属性,用于自定义每一项的渲染。我们可以这样:-将整个列表渲染成一个表格,包括表头和表体。但是Transfer组件的每个列表是一个`ul`,我们无法直接替换成`table`。因此,我们需要在`render`函数中返回一个`tr`元素,然后在Transfer组件的两个列表容器中,我们通过CSS将其内部结构改为`table`。但是这样操作比较复杂。考虑到这些,我们可以使用Transfer组件的另一个特性:`list-style`可以设置列表容器的样式,然后我们通过`render`返回一个表格行,然后在列表容器内部使用`table`标签包裹。但是Transfer组件的列表容器是`ul`,我们无法改变其标签。因此,我们放弃使用Transfer组件自带的列表容器,而是使用自定义渲染整个面板(通过插槽或者自定义整个组件)。但是antd-vue1.x的Transfer不支持插槽自定义整个面板。所以,这里我们采用两个Table组件和中间的控制按钮自己实现一个穿梭框,这样更灵活,也符合题目要求(两个表格)。自己实现的思路:-左侧表格:显示源数据(未选择的数据)-右侧表格:显示已选择的数据(目标数据)-中间有按钮:将左侧选中的数据移动到右侧,也可以将右侧选中的移回左侧,以及全移等。步骤:1.定义两个数组:leftData(源数据),rightData(目标数据)2.两个表格分别绑定leftData和rightData,并且每个表格都有多选框列3.定义两个数组:leftSelectedKeys(左侧选中行的key数组),rightSelectedKeys(右侧选中行的key数组)4.按钮事件:将左侧选中的key对应的数据从leftData中移除,并添加到rightData中,同时清空leftSelectedKeys;反之亦然。由于使用antd-vue,我们可以使用a-table组件,它自带了多选功能(通过rowSelection属性)。示例代码:注意:由于是Vue2,我们需要安装并引入antd-vue,并注册使用的组件(Table, Button, Icon等)。以下是具体实现:</think>以下是使用 Vue2 配合 Ant Design Vue (antd-vue) 实现表格穿梭框的完整解决方案: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Vue2 + Antd 穿梭框</title> <link href="https://cdn.jsdelivr.net/npm/ant-design-vue@1.7.8/dist/antd.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/ant-design-vue@1.7.8/dist/antd.min.js"></script> <style> .transfer-container { display: flex; justify-content: center; margin-top: 40px; } .table-container { width: 45%; border: 1px solid #e8e8e8; border-radius: 4px; overflow: hidden; } .transfer-actions { display: flex; flex-direction: column; justify-content: center; padding: 0 20px; } .action-button { margin: 10px 0; } .selected-count { margin-top: 10px; text-align: center; font-size: 12px; color: #999; } </style> </head> <body> <div id="app"> <a-card title="员工部门分配" style="width: 90%; margin: 20px auto"> <div class="transfer-container"> <!-- 左侧表格 --> <div class="table-container"> <a-table :row-selection="{ selectedRowKeys: leftSelectedKeys, onChange: onLeftSelectChange }" :columns="columns" :data-source="leftData" row-key="id" :pagination="false" > <template slot="title"> <div style="display: flex; justify-content: space-between; align-items: center;"> <span>未分配员工 ({{ leftData.length }})</span> <a-checkbox :indeterminate="leftIndeterminate" :checked="leftCheckAll" @change="onLeftCheckAllChange" > 全选 </a-checkbox> </div> </template> </a-table> </div> <!-- 中间操作按钮 --> <div class="transfer-actions"> <a-button type="primary" icon="right" class="action-button" :disabled="leftSelectedKeys.length === 0" @click="moveToRight" > 向右移动 </a-button> <a-button type="primary" icon="left" class="action-button" :disabled="rightSelectedKeys.length === 0" @click="moveToLeft" > 向左移动 </a-button> <a-button type="danger" icon="reload" class="action-button" @click="resetData" > 重置 </a-button> </div> <!-- 右侧表格 --> <div class="table-container"> <a-table :row-selection="{ selectedRowKeys: rightSelectedKeys, onChange: onRightSelectChange }" :columns="columns" :data-source="rightData" row-key="id" :pagination="false" > <template slot="title"> <div style="display: flex; justify-content: space-between; align-items: center;"> <span>已分配员工 ({{ rightData.length }})</span> <a-checkbox :indeterminate="rightIndeterminate" :checked="rightCheckAll" @change="onRightCheckAllChange" > 全选 </a-checkbox> </div> </template> </a-table> </div> </div> <div class="selected-count"> 已选择: {{ selectedItems.map(i => i.name).join(', ') || '无' }} </div> </a-card> </div> <script> Vue.use(antd); new Vue({ el: '#app', data() { return { // 表格列定义 columns: [ { title: '姓名', dataIndex: 'name', key: 'name', }, { title: '年龄', dataIndex: 'age', key: 'age', }, { title: '部门', dataIndex: 'department', key: 'department', } ], // 初始数据 originalData: [ { id: 1, name: '张三', age: 25, department: '技术部' }, { id: 2, name: '李四', age: 30, department: '市场部' }, { id: 3, name: '王五', age: 28, department: '财务部' }, { id: 4, name: '赵六', age: 32, department: '人事部' }, { id: 5, name: '钱七', age: 26, department: '技术部' } ], // 左侧表格数据 leftData: [], // 右侧表格数据 rightData: [], // 左侧选中项 leftSelectedKeys: [], // 右侧选中项 rightSelectedKeys: [], // 左侧全选状态 leftCheckAll: false, // 右侧全选状态 rightCheckAll: false, // 左侧半选状态 leftIndeterminate: false, // 右侧半选状态 rightIndeterminate: false }; }, computed: { // 当前选中的项目 selectedItems() { const leftSelected = this.leftData.filter(item => this.leftSelectedKeys.includes(item.id) ); const rightSelected = this.rightData.filter(item => this.rightSelectedKeys.includes(item.id) ); return [...leftSelected, ...rightSelected]; } }, created() { // 初始化数据 this.resetData(); }, methods: { // 初始化数据 resetData() { this.leftData = [...this.originalData]; this.rightData = []; this.leftSelectedKeys = []; this.rightSelectedKeys = []; this.updateLeftCheckState(); this.updateRightCheckState(); }, // 向左移动选中项 moveToLeft() { const selectedItems = this.rightData.filter(item => this.rightSelectedKeys.includes(item.id) ); // 从右侧移除 this.rightData = this.rightData.filter(item => !this.rightSelectedKeys.includes(item.id) ); // 添加到左侧 this.leftData = [...this.leftData, ...selectedItems]; // 重置选中状态 this.rightSelectedKeys = []; this.updateRightCheckState(); this.updateLeftCheckState(); }, // 向右移动选中项 moveToRight() { const selectedItems = this.leftData.filter(item => this.leftSelectedKeys.includes(item.id) ); // 从左侧移除 this.leftData = this.leftData.filter(item => !this.leftSelectedKeys.includes(item.id) ); // 添加到右侧 this.rightData = [...this.rightData, ...selectedItems]; // 重置选中状态 this.leftSelectedKeys = []; this.updateLeftCheckState(); this.updateRightCheckState(); }, // 左侧选择变化 onLeftSelectChange(selectedKeys) { this.leftSelectedKeys = selectedKeys; this.updateLeftCheckState(); }, // 右侧选择变化 onRightSelectChange(selectedKeys) { this.rightSelectedKeys = selectedKeys; this.updateRightCheckState(); }, // 左侧全选变化 onLeftCheckAllChange(e) { const checked = e.target.checked; this.leftSelectedKeys = checked ? this.leftData.map(item => item.id) : []; this.updateLeftCheckState(); }, // 右侧全选变化 onRightCheckAllChange(e) { const checked = e.target.checked; this.rightSelectedKeys = checked ? this.rightData.map(item => item.id) : []; this.updateRightCheckState(); }, // 更新左侧选择状态 updateLeftCheckState() { const total = this.leftData.length; const selected = this.leftSelectedKeys.length; this.leftCheckAll = total > 0 && selected === total; this.leftIndeterminate = selected > 0 && selected < total; }, // 更新右侧选择状态 updateRightCheckState() { const total = this.rightData.length; const selected = this.rightSelectedKeys.length; this.rightCheckAll = total > 0 && selected === total; this.rightIndeterminate = selected > 0 && selected < total; } } }); </script> </body> </html> ``` ### 功能说明: 1. **双表格穿梭框**: - 左侧表格显示未分配员工 - 右侧表格显示已分配员工 - 中间操作按钮实现数据双向移动 2. **全选功能**: - 每个表格都有全选复选框 - 支持全选/取消全选操作 - 半选状态显示(部分选中) 3. **选择状态管理**: - 使用 `selectedKeys` 管理选中项 - 实时更新全选和半选状态 - 底部显示当前选中项信息 4. **数据管理**: - 初始化时所有数据在左侧表格 - 支持数据双向移动 - 提供重置功能恢复初始状态 5. **Ant Design Vue 组件**: - 使用 `a-table` 实现表格展示 - 使用 `a-checkbox` 实现全选功能 - 使用 `a-button` 实现操作按钮 - 使用 `a-card` 作为容器 ### 关键实现细节: 1. **数据分离**: - 使用 `leftData` 和 `rightData` 分别管理两侧数据 - 通过数组过滤实现数据移动 2. **选择状态同步**: - 使用 `selectedKeys` 数组记录选中项 - 通过 `updateCheckState` 方法同步全选/半选状态 3. **性能优化**: - 使用 `row-key` 确保行标识唯一性 - 避免不必要的全表渲染 4. **UI 布局**: - 使用 Flex 布局实现三栏式结构 - 操作按钮垂直居中排列 - 表格标题显示数据计数
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值