在使用so-ui(类似于element-ui)组件库中的table的过程中,想要通过走
动态配置
生成表格,并将其封装成简单的通用组件。
实现步骤:
- 将每一列的属性提取写入js变量中,再通过遍历生成表格的每一列。
- 将表格的单元格,通过组件的
渲染函数
动态载入。- 单元格组件通过
JSX
方式书写。
接下去的文章会沿着我针对几个不同项目需求
对表格进行一步又一步的改造。
先说一下,table组件使用方式和我认为需要该进的方面。
html代码特别冗长
)。改造难点
)。 <so-table
:data="tableData"
stripe
style="width: 100%">
<so-table-column prop="date" label="日期" width="180">so-table-column>
<so-table-column label="操作" width="180">
<template slot-scope="scope">
<span class="span" @click="handleClick">查看span>
<span class="span">编辑span>
template>
so-table-column>
so-table>
我的经历过程(不同的项目需求)如下:
1. 没有自定的单元格。(每个单元格显示的里都是文本内容)
2. 有自定的单元格。(显示图片,换行,操作)
3. 可通用的表格组件。(封装)
因为,每一个
都是由固定的列属性值(比如:表头名字,宽度等)组成的。
所以,我就写了一个简单的 tableColumn
数据 。 然后对其进行遍历,生成表格。
<so-table :data="tableData" border style="width: 100%" empty-text="暂无数据">
<so-table-column
v-for="(col, index) in tableColumn" :key="index"
:fixed="col.fixed"
:prop="col.prop"
:label="col.label"
:width="col.width || ''"
:align="col.align || 'left'"
:header-align="col.headerAlign || 'left'"
:className="col.class"
:min-width="col.minWidth"
>
<template slot-scope="scope">
<span>
{{ formatData(scope.row[col.prop], col.handleType) }}
span>
template>
so-table-column>
so-table>
// js
/**
* tableColumn包含如下属性:
*
* @parmas prop 对应后台的字段
* @parmas label 表头字段
* @parmas width 宽度
* @parmas class 样式
* @parmas handleType 数据处理类型(与函数formatData结合使用)
* @parmas fixed 是否固定
* @parmas align 表头对其齐方式
*
*/
tableColumn: [{
prop: 'time',
label: '时间',
width: '120',
class: 'table-cell-wrap-lj',
handleType: 'time',
fixed: true
},
{
prop: 'remainMoney',
label: '金额(元)',
width: '120',
align: 'right',
handleType: 'awaitShowMoney'
}]
formatData(data, type) { // 对数据进行处理
if (type === 'money') {
return data ? format.moneyFixed2(data) : '0.00';
}else if (type === 'time') {
return data ? moment(data.split('.').join('/')).format('YYYY/MM/DD HH:mm') : '-';
}
return data || '-';
}
自认为的缺点:单元格内的数据处理,我用了 函数 formatData
结合 属性 handleType
的方式,感觉有一点麻烦。建议在给表格的tableData赋值前就直接将数据处理好
。
在表格插槽作用域中定义多个 template
,然后根据 属性type
显示对应的内容。
<so-table :data="tableData" border style="width: 100%" empty-text="暂无数据">
<so-table-column ...>
<template v-if="item.type=='btns'">
<span class="span" @click="handleClick">查看span>
<span class="span">编辑span>
template>
<template v-else-if="item.type =='image'">
<img :src="scope.row.mainPicture" />
template>
<template v-else>
{{ formatValue(scope.row[item.prop], item.handleType)}}
template>
so-table-column>
so-table>
自认为的缺点:这样走动态配置的表格只能用于一个业务场景(局限性
),针对每一个业务场景都要重新写一遍这个表格组件。(好麻烦的说~比如,上年省去的好几行表格配置的代码)
那么如何封装表格组件呢?使之能够一劳永逸。
我一开始想,是不是可以将 template
中的通过配置动态写入。
我尝试直接返回 html代码片段
然后使用 v-html
显示。然而,这样一方面会导致 组件库 的组件无法被渲染
。还有一方面,函数的定义使用也是难点。
<template v-else-if="item.type == 'special'">
<div v-html="item.config.way(scope.row[item.prop])">div>
template>
res = `
<button onclick="click">普通(正常显示,函数找不到)button>
<span onclick="console.log(1111)">普通(正常显示,函数正常)span>
<so-button @click="item.config.otherWay(scope.row && scope.row[item.prop])">组件失效so-button>
`;
我还尝试了用 渲染函数 VNodes
,看了好几遍vue的官网中的 渲染函数 & JSX,看的都是一知半解(脑阔疼~)。
因为我不是很懂 JSX
,所以真的让我用纯的VNodes
写复杂的单元格内容就让人有些头疼。
最后,还是要感谢我同事写的组件代码,使得我对 JSX
这个知识点有了新的认识和顿悟。
所以,我干了什么惊人之举呢?
我将写在 html 中 template
都提取出来放在 js 中,用 组件 (table-cell-content)
的形式动态渲染。
<so-table
:data="tableData"
border style="width: 100%"
empty-text="暂无数据"
class="table-bar"
v-if="tableData && tableColumns">
<so-table-column
v-for="(col, index) in tableColumns" :key="index"
:fixed="col.fixed"
:prop="col.prop"
:label="col.label"
:width="col.width || ''"
:align="col.align || 'left'"
:header-align="col.headerAlign || 'left'"
:className="col.class"
:min-width="col.minWidth"
>
<template slot-scope="scope">
<table-cell-content
:rowData="scope.row"
:col="col"
:handleC_oPrint="handleC_oPrint" :handleC_oDetail="handleC_oDetail"
>table-cell-content>
template>
so-table-column>
so-table>
// js
/* 单元格组件 */
export default {
components: {
/* 表格-单元格 【组件】 */
tableCellContent: {
/**
* table-cell-content 组件包含如下参数:
*
* @parmas rowData 该行所有数据字段
* @parmas col 改行的配置属性
*
* @funct handleC_oPrint 自定义函数
* @funct handleC_oDetail 自定义函数
*
*/
props: {
rowData: Object,
col: Object,
handleC_oPrint: Function,
handleC_oDetail: Function
},
data() {
return {
/* 表格-单元格 显示的内容 【组件】 */
/* 文字 */
normal:
<span>{this.rowData[this.col.prop]}</span>,
/* 车型信息 */
carInfo:
<div class="carInfo">
<div class="title">
{this.rowData.c_Name}显示图片OK
</div>
<div class="content">
<img src={this.rowData.c_Img} alt="" />
<div class="text">
<span>第一行 {this.rowData.one}</span>
<so-tooltip content="提示信息" placement="top">
<span>引用组件库组件ok</span>
</so-tooltip>
</div>
</div>
</div>,
/* 操作 */
operation:
<div class="operation">
{this.rowData.operation_print ? <p onClick={this.handleC_oPrint.bind(this, this.rowData)}>打印</p> : ''}
{this.rowData.operation_detail ? <p onClick={this.handleC_oDetail.bind(this, this.rowData)}>订单详情</p> : ''}
</div>
};
},
render() {
return (
(this.col.dataComponent && this[this.col.dataComponent]) ? this[this.col.dataComponent] : this.normal
);
}
}
}
}
然后,我就很顺利的用上了表格组件,同时支付样式组件库的组件的动态插入使用(比如:so-tooltip
)。
但是,表格组件中添加函数
还是需要手动添加修改。(值得继续反思)
在使用jsx的过程中遇到的问题(看着上面的代码可以思考一下):