Ant design vue table merges data items and customizes cell content

vue 2.x

ant view

Description of the problem: I recently received a new requirement to merge data items, as shown in the figure below. In fact, it is easy to understand just merging, cross-row settings, colSpan and rowSpan settings in HTML, row and column merging are enough, but ant It's a bit round in the middle. Up code

1. Two methods are needed, as follows, one is to organize the data source, and the other is to add setting items (I will talk about why we do this later). Put these two methods in the upper layer of vue, or you can put them in methods.


// rowSpan  合并列
// colSpan  合并行
const changeData = (data, field) => {
    let count = 0;//重复项的第一项
    let indexCount = 1;//下一项
    while (indexCount < data.length) {
        var item = data.slice(count, count + 1)[0];//获取没有比较的第一个对象
        if (!item[`${field}rowSpan`]) {
            item[`${field}rowSpan`] = 1;//初始化为1
        }
        if (item[field] === data[indexCount][field]) {//第一个对象与后面的对象相比,有相同项就累加,并且后面相同项设置为0
            item[`${field}rowSpan`]++;
            data[indexCount][`${field}rowSpan`] = 0;
        } else {
            count = indexCount;
        }
        indexCount++;
    }
    return data
}



/**
 * 
 * @param {*} data  数据源
 * @param {*} field  合并标识
 * @param {*} referenceList []数组  第一项为合并参照   后面的以第一项为参照
 * @param {*} reference2     除了referenceList中的项,其他都按照 reference2参照
 */
const changeData2 = (data, field, referenceList, reference2) => {
    let count = 0;//重复项的第一项
    let indexCount = 1;//下一项
    while (indexCount < data.length) {
        var item = data.slice(count, count + 1)[0];//获取没有比较的第一个对象
        if (!item[`${field}rowSpan`]) {
            item[`${field}rowSpan`] = 1;//初始化为1
        }
        if (referenceList.includes(field)) {
            if (item[field] === data[indexCount][field] && item[referenceList[0]] === data[indexCount][referenceList[0]]) {//第一个对象与后面的对象相比,有相同项就累加,并且后面相同项设置为0
                item[`${field}rowSpan`]++;
                data[indexCount][`${field}rowSpan`] = 0;
            } else {
                count = indexCount;
            }
        } else {
            if (item[field] === data[indexCount][field] && item[reference2] === data[indexCount][reference2] && item[referenceList[0]] === data[indexCount][referenceList[0]]) {//第一个对象与后面的对象相比,有相同项就累加,并且后面相同项设置为0
                item[`${field}rowSpan`]++;
                data[indexCount][`${field}rowSpan`] = 0;
            } else {
                count = indexCount;
            }
        }
        indexCount++;
    }
    return data
}

The following two methods are defined in 2 methods. Because my table is encapsulated, I need to dynamically transfer the column. Of course, you don’t need to encapsulate it, but you must dynamically organize the following data after obtaining the data. One of the methods requires Notice:

The customRender configuration item in the columns in the table component is explained as follows on the official website (version 1.7.8), which seems a bit confusing.

 Under normal circumstances, after I encapsulate it, I use this attribute to specify the configuration of a certain column. In the following code, the is_on_line column needs to add a slot to the encapsulated table to customize the display column. I won’t say much about this. There are many ants on the Internet. A case of table encapsulation.

 {
                    title: '状态',
                    key: 'is_on_line',
                    dataIndex: 'is_on_line',
                    width: '100px',
                    scopedSlots: { customRender: 'is_on_line' },
                },
...


<vi-table :columns="columns" :data="data" bordered :scroll="{ x: 1200 }" :pagination="false"
            :showPagination="false" paginationOption.sync="" @change="handleOnChange">
           

            <template slot="is_on_line" slot-scope="data">
                <span v-if="data.record.is_on_line == 'running'" class="statue-r statue-1">
                    在线
                </span>
                <span v-else class="statue-r statue-2"> 离线 </span>
            </template>

            
        </vi-table>

 Dynamically set columns, get background data, and transform the data

getColumn () {
            let _this = this

            //改造数据
            let propsList = ['channel_name', 'orderer_list'] //字段列名
            
            //整合数据源,将_this.data数据源中的两列'channel_name'和'orderer_list'整合下数据
            //changeData上面定义的方法 channel_name会变成channel_namerowSpan,用于记录我要合并的行,列的数量
            propsList.map(item => {
                _this.$set(_this, "data", changeData(_this.data, item))
            })

            //动态给columns赋值
            _this.columns = [
                {
                    title: '节点序号',
                    align: 'left',
                    width: '100px',
                    customRender: (text, record, index) => `${index + 1}`,
                },
                {
                    title: '通道名称',
                    dataIndex: 'channel_name',
                    key: 'channel_name',               
                    customRender: (value, row, index) => {
                        const obj = {
                            children: value,
                            attrs: {
                                class: 'verticalMiddle'
                            },
                        };
                        obj.attrs.rowSpan = row.channel_namerowSpan;
                        return obj;
                    }
                },

                {
                    title: 'Orderer节点',
                    dataIndex: 'orderer_list',
                    key: 'orderer_list',
                
                    scopedSlots: { customRender: 'orderer_list' },
                    customRender: (value, row, index) => {
                        const obj = {
                            children: _this.getRowTxt(value),
                            attrs: {
                                class: 'verticalMiddle'
                            },
                        };
                        obj.attrs.rowSpan = row.orderer_listrowSpan;

                        return obj;
                    },
                    customCell: (record, rowIndex) => {

                    }
                },
                {
                    title: '节点名称',
                    dataIndex: 'peer_name',
                    key: 'peer_name',
                },
                {
                    title: '组织名称',
                    dataIndex: 'org_name',
                    key: 'org_name',
                },
                {
                    title: '创建时间',
                    dataIndex: 'create_time',
                    key: 'create_time',
                    width: '180px',
                },
                {
                    title: '状态',
                    key: 'is_on_line',
                    dataIndex: 'is_on_line',
                    width: '100px',
                    scopedSlots: { customRender: 'is_on_line' },
                },
                {
                    title: '操作',
                    key: 'action',
                    width: '180px',
                    scopedSlots: { customRender: 'action' },
                },
            ]
        },

GetStatus () {
            //获取数据方法,里面也没啥,只是拿到接口数据,有我自己的小逻辑而已
            let _this = this
            BlockChainSetup.GetStatus({}).then((response) => {
                _this.spinning = false
                if (!_this.$common.checkStatue(response.data)) {
                    _this.$common.showMsg({
                        type: 'error',
                        content: response.data.msg,
                    })
                }

                let resData = { ...response.data.data }

                let peerArr = []
                if (resData.peer_list.length != 0) {
                    resData.peer_list.filter((item) => {
                        item.channel_name = resData.channel_name
                        item.orderer_list = resData.orderer_list
                        peerArr.push(item)
                    })
                    _this.$set(_this, 'data', peerArr)

                    _this.$nextTick(() => {
                        _this.getColumn()//改造数据
                    })
                } else {
                    _this.$set(_this, 'data', [{
                        channel_name: resData.channel_name,
                        orderer_list: resData.orderer_list
                    }])

                    _this.$nextTick(() => {
                        _this.getColumn()//改造数据
                    })
                }
            })
        }

In fact, there is nothing more at this point, but one thing that needs attention is the customRender item configuration. The jsx syntax format needs to be used here. The following settings are the definitions of each column. For columns that need to be merged, you need to add a costomRender function.

customRender: (value, row, index) => {
const obj = {
    children: _this.getRowTxt(value),//children用于显示你的内容是什么
    attrs: {//html中的标签属性,注意,class设置后,需要用到/deep/属性,否则你的样式不起作用
        class: 'verticalMiddle'
        //...其它定义属性,这里和render函数没什么区别,不做过多解释,
    },
};
obj.attrs.rowSpan = row.orderer_listrowSpan;//该项是设置你动态指定的列,第一个给出的两个方法你看看就明白了

return obj;//返回总设置,注意,该方法是一行row的设置,有N行,会执行N遍,当然,通过数据合并,会将你的数据源合并,所以数据源一致时,会执行N遍
},

The following is the getRowTxt method. My third column also needs to be merged. Moreover, it is an array, so the value of the array must be converted into a VNode.

  1. val:['aaaa','bbbb','cccc'], type value
  2. When converting to VNode, you can only use map(), not for, because for is not supported (for does not have the ability to return data, so it is temporarily useless and incomprehensible). At the same time, when writing JS, an external layer is added. Curly braces {JS code},
  3. What if you want to add other components, or ANT components? The red area below is the added a-button, such as the [red area in return] below. The attributes are defined above (sel_props). You cannot write [@click=''] here because Jsx syntax does not recognize it. Of course, you can add your own custom components in {}, but please note that attribute values ​​can only be written in {}.
  4. Finally, note that you must add a layer of div to the outermost layer, otherwise an error will be reported.

 return <div>

             {<a-button {...sel_props}>lalala</a-button>}

            </div>

getRowTxt (val) {
            let _this = this

            if (val && val.length != 0) {
                let sel_props = {
                    on: {
                        'click': val => {
                            _this.test();//methods中定义的方法
                        },//a-button的click方法,要遵循render函数写法

                    },
                };
                return <div>
                    {val.map((v) => {
                        return <p>{v}</p>
                    })}
                </div>    

                //  加了自定义组件写法
                //  return <div>
                //     {val.map((v) => {
                //         return <p>{v}</p>
                //     })}

                //     {<a-button {...sel_props}>lalala</a-button>}
                // </div>       
            }
},

 Add the effect of the custom component, and click to output the methods in methods

 

Guess you like

Origin blog.csdn.net/tdjqqq/article/details/125390212