運行
github地址
https://github.com/STRML/react-grid-layout
下載完代碼之后得哆,
npm install
npm run dev
首先讓代碼運行起來
lib/components/WidthProvider.jsx 解讀
// @flow
import React from "react";
import PropTypes from "prop-types";
import ReactDOM from "react-dom";
import type { ComponentType as ReactComponentType } from "react";
type WPProps = {
className?: string,
measureBeforeMount: boolean,
style?: Object
};
type WPState = {
width: number
};
/*
* A simple HOC that provides facility for listening to container resizes.
*/
// typescript 類型檢查
export default function WidthProvider<
Props,
ComposedProps: { ...Props, ...WPProps }
>(
ComposedComponent: ReactComponentType<Props>
): ReactComponentType<ComposedProps> {
return class WidthProvider extends React.Component<ComposedProps, WPState> {
static defaultProps = {
measureBeforeMount: false
};
static propTypes = {
// If true, will not render children until mounted. Useful for getting the exact width before
// rendering, to prevent any unsightly resizing.
measureBeforeMount: PropTypes.bool
};
state = {
width: 1280
};
mounted: boolean = false;
componentDidMount() {
this.mounted = true;
window.addEventListener("resize", this.onWindowResize);
// Call to properly set the breakpoint and resize the elements.
// Note that if you're doing a full-width element, this can get a little wonky if a scrollbar
// appears because of the grid. In that case, fire your own resize event, or set `overflow: scroll` on your body.
this.onWindowResize();
}
componentWillUnmount() {
this.mounted = false;
window.removeEventListener("resize", this.onWindowResize);
}
onWindowResize = () => {
if (!this.mounted) return;
// eslint-disable-next-line
const node = ReactDOM.findDOMNode(this); // Flow casts this to Text | Element
if (node instanceof HTMLElement)
this.setState({ width: node.offsetWidth });
};
render() {
const { measureBeforeMount, ...rest } = this.props;
if (measureBeforeMount && !this.mounted) {
return (
<div className={this.props.className} style={this.props.style} />
);
}
return <ComposedComponent {...rest} {...this.state} />;
}
};
}
一個特別簡單的高級函數(shù)迅耘,主要作用是綁定onresize事件蕊程,當組件改變的時候,重新計算元素的寬度
最主要的是這里
onWindowResize = () => {
if (!this.mounted) return;
// eslint-disable-next-line
const node = ReactDOM.findDOMNode(this); // Flow casts this to Text | Element
if (node instanceof HTMLElement)
this.setState({ width: node.offsetWidth });
};
lib/GridItem.jsx 解讀
/**
* Return position on the page given an x, y, w, h.
* left, top, width, height are all in pixels.
* @param {Number} x X coordinate in grid units.
* @param {Number} y Y coordinate in grid units.
* @param {Number} w W coordinate in grid units.
* @param {Number} h H coordinate in grid units.
* @return {Object} Object containing coords.
*/
calcPosition(
x: number,
y: number,
w: number,
h: number,
state: ?Object
): Position {
const { margin, containerPadding, rowHeight } = this.props;
const colWidth = this.calcColWidth();
const out = {
left: Math.round((colWidth + margin[0]) * x + containerPadding[0]),
top: Math.round((rowHeight + margin[1]) * y + containerPadding[1]),
// 0 * Infinity === NaN, which causes problems with resize constraints;
// Fix this if it occurs.
// Note we do it here rather than later because Math.round(Infinity) causes deopt
width:
w === Infinity
? w
: Math.round(colWidth * w + Math.max(0, w - 1) * margin[0]),
height:
h === Infinity
? h
: Math.round(rowHeight * h + Math.max(0, h - 1) * margin[1])
};
if (state && state.resizing) {
out.width = Math.round(state.resizing.width);
out.height = Math.round(state.resizing.height);
}
if (state && state.dragging) {
out.top = Math.round(state.dragging.top);
out.left = Math.round(state.dragging.left);
}
return out;
}
根據(jù)x,y計算出位置