2024-03-16 14:11:43 +08:00

277 lines
9.7 KiB
JavaScript

import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, ScrollView } from 'react-native';
import cascaderStyles from './styles';
const styles = StyleSheet.create(cascaderStyles);
import { Icon } from '../Icon';
import variables from '../../common/styles/variables';
import Tree from '../../common/utils/Tree';
export class Cascader extends Component {
constructor(props) {
super(props);
this.handlePress = (item, index) => {
const fieldKeys = this.getFieldKeys();
const { tree } = this.state;
if (item[fieldKeys.activeKey]) {
return;
}
if (item[fieldKeys.disabledKey]) {
return;
}
let tmpTree = this.resetActive(tree, item, fieldKeys);
tmpTree = Cascader.resetChecked(tmpTree, item, 'radio', true, fieldKeys);
const { checkedValue, checkedResult } = Cascader.getCheckedInfo(tmpTree, 'radio', fieldKeys);
const menu = this.getMenu(tmpTree, fieldKeys);
this.props.onChange && this.props.onChange(checkedValue, checkedResult);
this.setState({
tree: tmpTree,
menu,
});
};
this.state = {
...this.state,
...this.init(props)
};
}
static resetChecked(tree, item, checkType, checked, fieldKeys) {
let tmpTree = [
...tree,
];
if (checkType === 'checkbox') {
// TODO
}
if (checkType === 'radio') {
tmpTree = resetRadio(tmpTree, item, checked, fieldKeys);
}
return tmpTree;
function resetRadio(tree, item, checked, fieldKeys) {
let tmpTree = [
...tree
];
tmpTree = tmpTree.map((treeItem) => {
if (treeItem[fieldKeys.idKey] === item[fieldKeys.idKey]) {
return {
...treeItem,
[fieldKeys.checkedKey]: true
};
}
else {
return {
...treeItem,
[fieldKeys.checkedKey]: false
};
}
});
return tmpTree;
}
}
static getCheckedInfo(tree, checkType, fieldKeys) {
const checkedValue = [];
const checkedResult = [];
if (checkType === 'checkbox') {
// TODO
}
if (checkType === 'radio') {
tree.some((treeItem) => {
if (treeItem[fieldKeys.checkedKey]) {
checkedValue.push(treeItem[fieldKeys.idKey]);
return true;
}
return false;
});
}
checkedValue.forEach((valueItem, valueIndex) => {
const target = tree.filter((treeItem) => {
return treeItem[fieldKeys.idKey] === valueItem;
})[0];
const ancestors = Cascader.recursiveAncestors(tree, target, fieldKeys);
ancestors.push(target);
checkedResult[valueIndex] = ancestors;
});
return {
checkedValue,
checkedResult,
};
}
static recursiveAncestors(tree, item, fieldKeys, ret) {
ret = ret || [];
const parentItem = tree.filter((treeItem) => {
return treeItem[fieldKeys.idKey] === item[fieldKeys.pIdKey];
})[0];
if (parentItem) {
ret = ret.concat();
ret.unshift(parentItem);
return Cascader.recursiveAncestors(tree, parentItem, fieldKeys, ret);
}
else {
return ret;
}
}
init(props) {
const fieldKeys = this.getFieldKeys(props);
const { data, dataStructureType } = props;
const value = props.value || [];
let tree = new Tree({
type: dataStructureType,
...fieldKeys,
data: data
}).getData();
/**
* 重置 checked 状态
*/
value.forEach((valueItem) => {
const target = tree.filter((treeItem) => {
return treeItem[fieldKeys.idKey] === valueItem;
})[0];
if (!target) {
console.log(`${valueItem}在数据集合中不存在`);
return;
}
tree = Cascader.resetChecked(tree, target, 'radio', true, fieldKeys);
});
/**
* 重置 active 状态
*/
let activeItem;
if (value[0] != null) {
activeItem = tree.filter((treeItem) => {
return treeItem[fieldKeys.idKey] === value[0];
})[0];
}
tree = this.resetActive(tree, activeItem, fieldKeys);
const menu = this.getMenu(tree, fieldKeys);
return {
tree,
menu,
};
}
resetActive(tree, activeItem, fieldKeys) {
if (!activeItem) {
return tree;
}
let tmpTree = [
...tree,
];
tmpTree = tmpTree.map((treeItem) => {
return {
...treeItem,
[fieldKeys.activeKey]: false
};
});
recursive(activeItem);
return tmpTree;
function recursive(activeItem) {
tmpTree = tmpTree.map((treeItem) => {
if (treeItem[fieldKeys.idKey] === activeItem[fieldKeys.idKey]) {
return {
...treeItem,
[fieldKeys.activeKey]: true
};
}
else {
return treeItem;
}
});
const parentItem = tmpTree.filter((treeItem) => {
return treeItem[fieldKeys.idKey] === activeItem[fieldKeys.pIdKey];
})[0];
if (parentItem) {
recursive(parentItem);
}
}
}
getMenu(tree, fieldKeys) {
const menu = [
tree.filter((treeItem) => {
return treeItem[fieldKeys.pIdKey] == null;
})
];
recursive(menu[0]);
return menu;
function recursive(list) {
list.some((item) => {
if (item[fieldKeys.activeKey]) {
const tmpList = tree.filter((treeItem) => {
return treeItem[fieldKeys.pIdKey] === item[fieldKeys.idKey];
});
if (tmpList && tmpList.length) {
menu.push(tmpList);
recursive(tmpList);
}
return true;
}
return false;
});
}
}
getFieldKeys(props) {
props = props || this.props;
const { fieldKeys } = props;
return {
idKey: fieldKeys.idKey || 'id',
pIdKey: fieldKeys.pIdKey || 'pId',
labelKey: fieldKeys.labelKey || 'label',
childrenKey: fieldKeys.childrenKey || 'children',
activeKey: fieldKeys.activeKey || 'active',
checkedKey: fieldKeys.checkedKey || 'checked',
disabledKey: fieldKeys.disabledKey || 'disabled'
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.value !== this.props.value ||
nextProps.data !== this.props.data) {
this.setState({
...this.init(nextProps)
});
}
}
componentDidMount() {
}
renderMenuItem(menuItem, menuIndex, menu) {
const { proportion } = this.props;
const style = {
flex: proportion[menuIndex] || 1,
borderRightColor: variables.mtdBorderColor,
borderRightWidth: menuIndex < menu.length - 1 ? StyleSheet.hairlineWidth : 0
};
return (React.createElement(View, { style: style, key: menuIndex },
React.createElement(ScrollView, null, menuItem.map((item, index) => {
return this.renderItem(item, index);
}))));
}
renderItem(item, index) {
const fieldKeys = this.getFieldKeys();
const { tree } = this.state;
const isLeafNode = this.props.isLeafNode
? this.props.isLeafNode(item)
: !(item && item[fieldKeys.childrenKey] && item[fieldKeys.childrenKey].length);
const active = item[fieldKeys.activeKey];
return (React.createElement(TouchableOpacity, { key: index, onPress: this.handlePress.bind(this, item, index) }, this.props.renderItem ? this.props.renderItem(item, index) :
React.createElement(View, { style: [
styles.item,
active ? { backgroundColor: variables.mtdFillGray } : {},
] },
React.createElement(Text, { style: [
styles.itemText,
active ? { color: variables.mtdBrandPrimaryDark, fontWeight: 'bold' } : {},
], ellipsizeMode: 'middle' }, item[fieldKeys.labelKey]),
!isLeafNode ? React.createElement(Icon, { source: require(`../../common/images/icons/angle-right.png`), size: variables.mtdFontSizeM, tintColor: variables.mtdGrayLighter }) : null)));
}
render() {
const { style } = this.props;
const { menu } = this.state;
return (React.createElement(View, { style: [styles.container, style] }, menu.map((item, index) => {
return this.renderMenuItem(item, index, menu);
})));
}
}
Cascader.displayName = 'Cascader';
Cascader.defaultProps = {
data: [],
dataStructureType: 'nested',
value: [],
fieldKeys: {},
proportion: [2, 1, 1],
onChange: null,
renderItem: null
};
//# sourceMappingURL=index.js.map