zarm-mobile
Version:
UI for react.js
183 lines (158 loc) • 4.98 kB
JSX
import React, { Component } from 'react';
import classNames from 'classnames';
import ZScroller from 'zscroller';
import { isChildrenEqual } from './utils';
function getChildMember(child, m) {
return child[m];
}
function toChildrenArray(children) {
return children;
}
class Column extends Component {
constructor(props) {
super(props);
let selectedValueState;
const { selectedValue, defaultSelectedValue, children } = this.props;
if (selectedValue !== undefined) {
selectedValueState = selectedValue;
} else if (defaultSelectedValue !== undefined) {
selectedValueState = defaultSelectedValue;
} else if (children && children.length) {
selectedValueState = children[0][this.props.valueMember];
}
this.state = {
selectedValue: selectedValueState,
};
}
componentDidMount() {
this.itemHeight = this.indicator.offsetHeight;
// console.log('this.itemHeight -> ', this.indicator.offsetHeight);
// compact
this.content.style.padding = `${this.itemHeight * 3}px 0`;
this.zscroller = new ZScroller(this.content, {
scrollingX: false,
snapping: true,
penetrationDeceleration: 0.1,
minVelocityToKeepDecelerating: 0.5,
scrollingComplete: this.scrollingComplete.bind(this),
});
this.zscroller.setDisabled(this.props.disabled);
this.zscroller.scroller.setSnapSize(0, this.itemHeight);
this.select(this.state.selectedValue);
}
componentWillReceiveProps(nextProps) {
if ('selectedValue' in nextProps) {
this.setState({
selectedValue: nextProps.selectedValue,
});
}
this.zscroller.setDisabled(nextProps.disabled);
}
shouldComponentUpdate(nextProps, nextState) {
return this.state.selectedValue !== nextState.selectedValue
|| !isChildrenEqual(this.props.children, nextProps.children, this.props.pure);
}
componentDidUpdate() {
this.zscroller.reflow();
this.select(this.state.selectedValue);
}
componentWillUnmount() {
this.zscroller.destroy();
}
getValue() {
return this.props.selectedValue ? this.props.selectedValue
: this.props.children && this.props.children[0] && this.props.children[0][this.props.valueMember];
}
scrollingComplete() {
const { top } = this.zscroller.scroller.getValues();
if (top >= 0) {
this.doScrollingComplete(top);
}
}
fireValueChange(selectedValue) {
if (selectedValue !== this.state.selectedValue) {
if (!('selectedValue' in this.props)) {
this.setState({
selectedValue,
});
}
this.props.onValueChange(selectedValue);
}
}
scrollTo(top) {
this.zscroller.scroller.scrollTo(0, top);
}
select(value) {
const children = toChildrenArray(this.props.children);
for (let i = 0, len = children.length; i < len; i += 1) {
if (getChildMember(children[i], this.props.valueMember) === value) {
this.selectByIndex(i);
return;
}
}
this.selectByIndex(0);
}
selectByIndex(index) {
if (index < 0 || index >= toChildrenArray(this.props.children).length || !this.itemHeight) {
return;
}
this.scrollTo(index * this.itemHeight);
}
doScrollingComplete(top) {
let index = top / this.itemHeight;
const floor = Math.floor(index);
if (index - floor > 0.5) {
index = floor + 1;
} else {
index = floor;
}
const children = toChildrenArray(this.props.children);
index = Math.min(index, children.length - 1);
const child = children[index];
if (child) {
this.fireValueChange(getChildMember(child, this.props.valueMember));
} else if (console.warn) {
console.warn('child not found', children, index);
}
}
render() {
const {
children, prefixCls,
className, itemStyle,
indicatorStyle, valueMember,
} = this.props;
const { selectedValue } = this.state;
const itemClassName = `${prefixCls}-cascader-item`;
const selectedItemClassName = `${itemClassName} ${prefixCls}-cascader-item-selected`;
const items = children.map((item) => {
return (
<div
style={itemStyle}
className={selectedValue === item[valueMember] ? selectedItemClassName : itemClassName}
key={item.value} >
{item.label}
</div>
);
});
const pickerCls = {
[className]: !!className,
[`${prefixCls}-cascader`]: true,
};
return (
<div
className={classNames(pickerCls)} >
<div className={`${prefixCls}-cascader-indicator`} ref={(indicator) => { this.indicator = indicator; }} style={indicatorStyle} />
<div className={`${prefixCls}-cascader-content`} ref={(content) => { this.content = content; }}>
{items}
</div>
</div>
);
}
}
Column.defaultProps = {
// prefixCls: 'za-cascaderpicker',
prefixCls: 'za-picker',
pure: true,
onValueChange: () => {},
};
export default Column;