Grids.jsx源码
/root/workspace/actionview/av-github-source-code/actionview-fe/app/components/gantt/Grids.jsx
import React, { PropTypes, Component } from 'react';
import _ from 'lodash';
const $ = require('$');
const GridItem = require('./GridItem');
const GridEmptyItem = require('./GridEmptyItem');
export default class Grids extends Component {
constructor(props) {
super(props);
}
static propTypes = {
cellWidth: PropTypes.number.isRequired,
collection: PropTypes.array.isRequired,
dates: PropTypes.object.isRequired,
foldIssues: PropTypes.array.isRequired,
markedIssue: PropTypes.object.isRequired,
today: PropTypes.string.isRequired
}
render() {
const {
cellWidth,
collection,
dates,
foldIssues,
markedIssue,
today=''
} = this.props;
let offset = 0;
let clientWidth = document.body.clientWidth;
let scrollTop = 0;
let clientHeight = document.body.clientHeight;
if ($('div.ganttview-slide-container').length > 0) {
offset = $('div.ganttview-slide-container').scrollLeft();
clientWidth = $('div.ganttview-slide-container').get(0).clientWidth;
scrollTop = $('div.ganttview-slide-container').scrollTop();
clientHeight = $('div.ganttview-slide-container').get(0).clientHeight;
}
const dates2 = _.flatten(_.values(dates));
const newCollection = _.reject(collection, (v) => v.parent && foldIssues.indexOf(v.parent.id) != -1);
const topInd = _.max([ _.floor(scrollTop / 31) - 10, 0 ]);
const bottomInd = _.min([ _.floor((scrollTop + clientHeight) / 31) + 10, newCollection.length - 1 ]);
return (
<div
className='ganttview-grid'
style={ { width: dates2.length * cellWidth + 'px' } }>
{ _.map(newCollection, (v, key) => {
if (key < topInd || key > bottomInd) {
return (
<GridEmptyItem
key={ v.id }
cellWidth={ cellWidth }
dates={ dates2 } />
);
} else {
return (
<GridItem
key={ v.id }
offset={ offset }
clientWidth={ clientWidth }
cellWidth={ cellWidth }
dates={ dates2 }
issue={ v }
markedIssue={ markedIssue }
today={ today } />
);
}
} ) }
</div>);
}
}
源码解读
这段代码定义了一个名为 Grids
的 React 组件,用于渲染甘特图中的网格行。这个组件负责根据传入的属性动态生成网格行,并根据折叠状态决定哪些行需要渲染详细信息,哪些行仅渲染空白占位符。
代码分析
导入模块
import React, { PropTypes, Component } from 'react';
import _ from 'lodash';
const $ = require('$');
const GridItem = require('./GridItem');
const GridEmptyItem = require('./GridEmptyItem');
-
React
:React 的核心库。 -
PropTypes
:用于定义组件的 prop 类型检查。 -
lodash
:一个实用工具库,提供了很多常用的函数,如_.flatten
和_.reject
。 -
$
:jQuery 库,用于 DOM 操作。 -
GridItem
:一个子组件,用于渲染包含具体任务信息的网格行。 -
GridEmptyItem
:一个子组件,用于渲染空白占位符的网格行。
定义组件类
export default class Grids extends Component {
constructor(props) {
super(props);
}
-
Grids
类继承自Component
,表示这是一个 React 组件。 -
constructor
构造函数初始化组件,并调用父类构造函数super(props)
来初始化父类属性。
定义 prop 类型
static propTypes = {
cellWidth: PropTypes.number.isRequired,
collection: PropTypes.array.isRequired,
dates: PropTypes.object.isRequired,
foldIssues: PropTypes.array.isRequired,
markedIssue: PropTypes.object.isRequired,
today: PropTypes.string.isRequired
}
propTypes
是一个静态属性,用于定义组件接受的 prop 类型。
-
cellWidth
:每个单元格的宽度。 -
collection
:一个数组,包含所有任务信息。 -
dates
:一个对象,其键为月份,值为该月每一天的信息。 -
foldIssues
:一个数组,包含需要折叠的任务 ID。 -
markedIssue
:一个对象,表示标记的任务。 -
today
:今天的日期字符串。
渲染方法
render() {
const {
cellWidth,
collection,
dates,
foldIssues,
markedIssue,
today=''
} = this.props;
let offset = 0;
let clientWidth = document.body.clientWidth;
let scrollTop = 0;
let clientHeight = document.body.clientHeight;
if ($('div.ganttview-slide-container').length > 0) {
offset = $('div.ganttview-slide-container').scrollLeft();
clientWidth = $('div.ganttview-slide-container').get(0).clientWidth;
scrollTop = $('div.ganttview-slide-container').scrollTop();
clientHeight = $('div.ganttview-slide-container').get(0).clientHeight;
}
const dates2 = _.flatten(_.values(dates));
const newCollection = _.reject(collection, (v) => v.parent && foldIssues.indexOf(v.parent.id) != -1);
const topInd = _.max([ _.floor(scrollTop / 31) - 10, 0 ]);
const bottomInd = _.min([ _.floor((scrollTop + clientHeight) / 31) + 10, newCollection.length - 1 ]);
return (
<div
className='ganttview-grid'
style={ { width: dates2.length * cellWidth + 'px' } }>
{ _.map(newCollection, (v, key) => {
if (key < topInd || key > bottomInd) {
return (
<GridEmptyItem
key={ v.id }
cellWidth={ cellWidth }
dates={ dates2 } />
);
} else {
return (
<GridItem
key={ v.id }
offset={ offset }
clientWidth={ clientWidth }
cellWidth={ cellWidth }
dates={ dates2 }
issue={ v }
markedIssue={ markedIssue }
today={ today } />
);
}
} ) }
</div>);
}
}
render
方法返回组件的 JSX 结构。
- 解构赋值
const { ... } = this.props
来提取传入的 props。 - 获取当前滚动位置和可视区域尺寸:
-
offset
:水平滚动偏移量。 -
clientWidth
:可视区域的宽度。 -
scrollTop
:垂直滚动位置。 -
clientHeight
:可视区域的高度。
- 如果存在
.ganttview-slide-container
元素,则从该元素获取滚动和尺寸信息。 - 计算扁平化的日期数组
dates2
。 - 计算过滤后的任务集合
newCollection
,排除需要折叠的任务。 - 计算顶部和底部索引
topInd
和bottomInd
,用于确定哪些任务需要渲染。 - 渲染一个
<div>
容器,作为网格的基础。 - 使用
_.map
循环遍历newCollection
。
- 如果索引小于
topInd
或大于bottomInd
,则渲染GridEmptyItem
,表示该行仅需要空白占位符。 - 否则,渲染
GridItem
,表示该行需要详细信息。
- 每个任务行都有唯一的
key
属性,以便 React 可以高效地管理 DOM 更新。
总结
这个 Grids
组件负责渲染甘特图中的网格行,根据传入的 props
动态生成网格行,并根据折叠状态决定哪些行需要渲染详细信息,哪些行仅渲染空白占位符。组件还考虑了滚动位置和可视区域尺寸,以优化渲染性能。
通过这种方式,组件能够灵活地适应不同的数据和布局需求,为用户提供清晰的任务进度视图,并且在滚动时只渲染可视区域的任务行,提高渲染效率。