大家好,最近天冷了,注意多穿衣服保暖哟
最近接到了这样一个需求,大概就是画出来一个机票行程单这样的页面。看到这个页面大家首选方案是什么table还是div+css3,我首选方案是table。因为这个页面除了表格稍微复杂了点,其他都很简单。用div+css3的话还需要调试样式再各大浏览器的兼容性,注定是要写超多的css样式。而table完全不需要担心,何必多次一举呢。我们的口号是用最简单的编码逻辑实现最复杂的功能,能写一行代码实现的功能坚决不写两行代码实现。
接下来就要用到table表格了,再使用table表格的时候要确定好表格的行和列,下边这个看着好像挺简单的,但是要是确定行数和列数肉眼还是看不出来的。因此这里我特地用excel先做了一个这样的表格出来,这样就很快可以确定出表格的行和列,每个单元格所占的行和列也就快速确定出来了,确定好之后就可以愉快的画我们的table了。表格画好之后,有些宽度和高度可能需要重新设置下就好了,再调下颜色和字体,完美解决了。
当然不止这一种车票用这样的形式,还有客运汽车票和火车票也是用的原生table来画的。项目中使用的react开发的,做的过程中发现都是使用的原生table,那是不是可以把table这一部分提取成一个组件来使用呢。说干就干,提取过程中首先就是确定好参数,确定好是要渲染tr还是td还是th标签,确定好之后,用循环来渲染table中的行和列就可以了。
贴下代码
table.jsx
import React from 'react';
import PropTypes from 'prop-types';
import Item from './RenderItem';
const Table = ({ tableList }) => {
return (
<div>
<table>
<tbody>
{tableList.map((item) => (
<tr align={item.align} key={item.id}>
{item.children.map((childItem) => (
<Item
key={childItem.data}
type={item.type}
isPrice={childItem.isPrice}
isTitle={childItem.isTitle}
{...childItem}
/>
))}
</tr>
))}
</tbody>
</table>
</div>
);
};
Table.propTypes = {
tableList: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
isParent: PropTypes.bool,
type: PropTypes.string,
align: PropTypes.string,
children: PropTypes.arrayOf(
PropTypes.shape({
data: PropTypes.string,//唯一key值
width: PropTypes.string,//单元格宽度
content: PropTypes.string,//单元格内容
isPrice: PropTypes.bool,//是否是价格的单元格,后续可能需要
isTitle: PropTypes.bool,//是否是标题的单元格,后续可能需要
className: PropTypes.string,//单元格的class属性
colSpan: PropTypes.string,//所占的列数
rowSpan: PropTypes.string,//所占的行数
}),
),
}),
),
};
Table.defaultProps = {
tableList: [],
};
export default Table;
//RenderItem.jsx
import React from 'react';
import PropTypes from 'prop-types';
const Item = ({ type, isTitle, isPrice, ...rest }) => {
if (type === '0') {
return <th {...rest}>{rest.content}</th>;
}
if (type === '1') {
return <td {...rest}>{rest.content}</td>;
}
return <td {...rest}>{rest.content}</td>;
};
Item.propTypes = {
type: PropTypes.string.isRequired,
isTitle: PropTypes.bool,
isPrice: PropTypes.bool,
};
Item.defaultProps = {
isTitle: false,
isPrice: false,
};
export default Item;
//参数格式如下所示
const list = [
{
id: '1',
isParent: true,
type: '0',
align: 'center',
children: [
{
data: '1',
colSpan: '2',
rowSpan: '2',
height: '80px',
content: '',
isPrice: false,
},
{
data: '2',
width: '105px',
content: '姓名',
isPrice: false,
isTitle: true,
className: styles['text-color'],
},
{
data: '3',
width: '175px',
content: '身份证',
isPrice: false,
isTitle: true,
className: styles['text-color'],
},
{
data: '4',
width: '115px',
rowSpan: '2',
content: '票价',
isPrice: false,
isTitle: true,
className: styles['text-color'],
},
{
data: '5',
rowSpan: '2',
colSpan: '2',
width: '240px',
content: selectInvoice.fare,
isPrice: true,
},
],
},
{
id: '2',
isParent: true,
type: '1',
align: 'center',
children: [
{
data: '1',
content: selectInvoice.passengerName,
isTitle: false,
},
{
data: '2',
content: '',
isTitle: false,
},
],
},
{
id: '3',
isParent: true,
type: '0',
align: 'center',
children: [
{
data: '1',
width: '120px',
height: '40px',
content: '乘车日期',
isTitle: true,
className: styles['text-color'],
},
{
data: '2',
width: '120px',
height: '40px',
content: '乘车时间',
isTitle: true,
className: styles['text-color'],
},
{
data: '3',
content: '座位号',
isTitle: true,
className: styles['text-color'],
},
{
data: '4',
content: '检票口',
isTitle: true,
className: styles['text-color'],
},
{
data: '5',
content: '车次',
isTitle: true,
className: styles['text-color'],
},
{
data: '6',
width: '240px',
content: '座位类别',
isTitle: true,
className: styles['text-color'],
},
],
},
{
id: '4',
isParent: true,
type: '1',
align: 'center',
children: [
{
data: '1',
height: '40px',
content: byDate,
},
{
data: '2',
height: '40px',
content: '',
},
{
data: '3',
height: '40px',
content: '',
},
{
data: '4',
height: '40px',
content: '',
},
{
data: '5',
height: '40px',
content: selectInvoice.toolsNumber,
},
{
data: '6',
height: '40px',
content: '',
},
],
},
];
再写成组件的时候,出现了一个错误,虽然可以正常显示,但是控制台一直打印错误
Warning: Failed propType: checker is not a function Check the render method of Chart
就是这么个错误,当时就有点懵逼,这个
checker 并没有定义啊,为什么会报错呢。后来再stackover上找到了类似的错误,下边也给出了解决方案。最后发现是使用PropTypes定义变量的时候,变量的类型给搞错了。最后修改过来完美解决。
整理下提取组件的思路
1、可以先再不提取的情况下画出完整的页面,然后确定页面中哪些部分是可以抽取出来给组件化的
2、确定好组件需要的参数,哪些是必需的,哪些是非必需的
3、如果只是简单的查看不需要对组件操作,直接返回一个界面就可以的。如果页面中有需要操作的,可以使用useRef的形式达到父子组件间传值
以上只是个简单的提取组件的案例,再接下来的开发中再接再厉,争取可以有更多组件化开发的思想和实践。我再优化下这个组件,争取能发到公共的npm库上