blob: e478a6a3c954c4c852c4e4e3e382137d031c860a [file] [log] [blame]
import React from 'react';
import ReactDOM from 'react-dom';
import { autobind } from 'core-decorators';
import classnames from 'classnames';
import { throttle } from '../../../utils';
import './index.scss';
class Slider extends React.Component {
constructor(props) {
super(props);
this.container = null;
this.state = {
screenIndex: 0,
visibleNum: 1,
};
}
componentDidMount() {
this.throttleAdjust = throttle(() => {
this.setState({
visibleNum: this.getVisibleNum(),
});
}, 200);
window.addEventListener('resize', this.throttleAdjust);
// 做重新布局
/* eslint-disable react/no-did-mount-set-state */
this.setState({
visibleNum: this.getVisibleNum(),
});
}
componentWillUnmount() {
window.removeEventListener('resize', this.throttleAdjust);
}
@autobind
getVisibleNum() {
// 比较粗略的计算,假定一屏的子节点外边距之和不会超过一个子节点的宽度
/* eslint-disable react/no-find-dom-node */
let result = 1;
const containerWidth = this.container.getBoundingClientRect().width;
const childWidth = this.sliderItemChild0.getBoundingClientRect ? this.sliderItemChild0.getBoundingClientRect().width : ReactDOM.findDOMNode(this.sliderItemChild0).getBoundingClientRect().width;
if (containerWidth && childWidth) {
result = Math.floor(containerWidth / childWidth);
}
// 有可能result为0,下面的除法就会出现分母为0,从而导致得出Inifity,无限循环导致浏览器崩溃
return result || 1;
}
@autobind
getListWidth() {
let width = 0;
const { children } = this.props;
const { visibleNum } = this.state;
const len = React.Children.count(children);
// 最终分成的屏数
const splitNum = Math.ceil(len / visibleNum);
if (this.container) {
const containerWidth = this.container.getBoundingClientRect().width;
width = containerWidth * splitNum;
}
return width;
}
changeScreen(i) {
const { screenIndex } = this.state;
// const total = React.Children.count(this.props.children);
if (i !== screenIndex) {
this.setState({
screenIndex: i
});
}
}
@autobind
renderSliderList() {
const { children } = this.props;
const { screenIndex, visibleNum } = this.state;
const splitGroup = [];
const len = React.Children.count(children);
// 分成的屏数
const splitNum = Math.ceil(len / visibleNum);
/* eslint-disable no-plusplus*/
for (let i = 0; i < splitNum; i++) {
splitGroup.push(Array.from(children).slice(i * visibleNum, (i + 1) * visibleNum));
}
return (
<div
className="slider-list"
style={{
transform: `translateX(-${screenIndex * ((this.container && this.container.getBoundingClientRect().width) || 0)}px)`,
transition: 'transform 500ms ease',
width: this.getListWidth(),
}}
>
{splitGroup.map((group, i) => {
return (
<div
className="slider-screen"
style={{ width: (this.container && this.container.getBoundingClientRect().width) || 0 }}
key={i}
ref={(node) => { this[`sliderScreen${i}`] = node; }}
>
{
group.map((child, j) => (
<div
className="slider-item"
key={j}
>
{React.cloneElement(child, {
ref: (node) => {
this[`sliderItemChild${(i * visibleNum) + j}`] = node;
}
})}
</div>
)
)
}
</div>
);
})}
</div>
);
}
@autobind
renderControl() {
const { children } = this.props;
const { screenIndex, visibleNum } = this.state;
const len = React.Children.count(children);
// 分成的屏数
const splitNum = Math.ceil(len / visibleNum);
const temp = [];
for (let i = 0; i < splitNum; i++) {
temp.push((
<span
key={i}
className={
classnames({
'slider-control-item': true,
'slider-control-item-active': i === screenIndex,
})
}
onClick={this.changeScreen.bind(this, i)}
/>
));
}
return (
<div className="slider-control">
{temp}
</div>
);
}
render() {
return (
<div className="slider" ref={(node) => { this.container = node; }}>
{this.renderSliderList()}
{this.renderControl()}
</div>
);
}
}
export default Slider;