mp-colorui
Version:
MP ColorUI 是一款基于 Taro 框架并且联合 Color-UI CSS 库开发的多端 UI 组件库(支持小程序端和H5端)
227 lines • 6.7 kB
JavaScript
import Nerv from "nervjs";
import Taro from "@tarojs/taro-h5";
import { View } from "@tarojs/components";
import ClCheckbox from "../checkbox/index";
import ClIcon from "../icon/index";
import ClText from "../text/index";
import ClFlex from "../flex/index";
import { generateId } from "../../lib/index";
import "./index.scss";
export default class ClTree extends Taro.Component {
constructor(props) {
super(props);
this.state = {
list: [],
originList: [],
flatList: []
};
}
dealLevel({ list, parentId, deep, levelId }) {
if (!list) return;
let deepIndex = deep || 0;
deepIndex++;
const temp = list.map((item, listIndex) => {
const id = listIndex + 1;
const newLevelId = levelId ? `${levelId}-${id}` : `${id}`;
return {
...item,
deepIndex,
id,
parent: parentId,
childrenCheck: [],
commonId: generateId(),
levelId: newLevelId,
children: this.dealLevel({
list: item.children,
parentId: id,
deep: deepIndex,
levelId: newLevelId
})
};
});
return temp;
}
openItem(item) {
const thisOpen = !item.open;
const originItem = this.getTreeItem(item.commonId);
originItem.open = thisOpen;
const { originList } = this.state;
const newList = this.flatList(originList);
this.setState({
list: newList
});
}
clickItem(item) {
const { onClickItem } = this.props;
onClickItem && onClickItem(item);
}
getTreeItem(id) {
const { originList } = this.state;
let result;
function getItem(list) {
if (!result) {
for (let item of list) {
result = result ? result : item.commonId === id ? item : undefined;
if (item.children && !result) {
getItem(item.children);
}
}
}
}
getItem(originList);
return result;
}
changeChecked(commonId = [], item) {
const { flatList } = this.state;
const { onCheckedChange } = this.props;
const id = item.commonId;
const checked = commonId.length > 0;
const data = flatList.find(item => item.commonId === id);
const levelIdArr = item.levelId.split("-");
const allLevelChildren = flatList.filter(child => {
const levelArr = child.levelId.split("-");
return levelIdArr.every((item, index) => item === levelArr[index]) && item.deepIndex < child.deepIndex;
});
const allParent = flatList.filter(father => {
if (item.deepIndex <= father.deepIndex) return false;
let i = 0;
let result = true;
const levelArr = father.levelId.split("-");
while (i < father.deepIndex) {
result = result && levelArr[i] === levelIdArr[i];
i++;
}
return result;
});
allLevelChildren.forEach(item => {
item.checked = checked;
item.someCheck = false;
});
const father = allParent.find(parent => parent.deepIndex === item.deepIndex - 1);
data.checked = checked;
onCheckedChange && onCheckedChange(data);
const maxDeep = allParent.length;
let i = maxDeep;
if (checked) {
data.someCheck = false;
if (father) {
father.someCheck = father.children.some(item => !item.checked || item.someCheck);
}
let result = true;
while (i > 0) {
const current = allParent.find(item => item.deepIndex === i);
result = result && current.children.every(child => child.checked && !child.someCheck);
current.someCheck = !result;
current.checked = checked;
i--;
}
} else {
allParent.forEach(item => item.someCheck = true);
if (father) {
father.checked = father.children.some(item => item.checked);
}
while (i > 0) {
const current = allParent.find(item => item.deepIndex === i);
current.checked = current.children.some(child => child.checked);
i--;
}
}
this.setState({
flatList: [...flatList],
list: [...this.state.list]
});
}
renderItem(item) {
const { color, showCheck } = this.props;
return <View style={{
paddingLeft: Taro.pxTransform((item.deepIndex - 1) * 20)
}}>
<ClFlex align={"center"}>
<View style={{
transform: `rotate(${item.open ? 180 : 90}deg)`,
visibility: item.children ? "initial" : "hidden"
}} onClick={this.openItem.bind(this, item)}>
<ClIcon iconName={"triangleupfill"} size={"small"} />
</View>
{showCheck ? <ClCheckbox type={"normal"} shape={"round"} more={item.someCheck} color={color} checkboxGroup={[{
checked: item.checked,
key: "",
value: item.commonId,
disabled: item.disabled
}]} onChange={commonId => {
this.changeChecked.call(this, commonId, item);
}} /> : ""}
<View onClick={this.clickItem.bind(this, item)}>
<ClText text={item.name} />
</View>
</ClFlex>
</View>;
}
flatList(list) {
const flat = [];
function flatFn(list) {
list.forEach(item => {
flat.push(item);
if (item.children && item.open) {
flatFn(item.children);
}
});
}
flatFn(list);
return flat;
}
flatAllArr(list) {
const category = [];
function categoryFn(list = []) {
list.forEach(item => {
category.push(item);
if (item.children) {
categoryFn(item.children);
}
});
}
categoryFn(list);
return category;
}
updateData(data) {
const dealArr = this.dealLevel({
list: data,
parentId: undefined
});
const flatArr = this.flatList(dealArr);
const flatList = this.flatAllArr(dealArr);
this.setState({
list: flatArr,
originList: dealArr,
flatList
}, () => {
const checkedList = flatList.filter(item => item.checked);
const openList = flatList.filter(item => item.open);
openList.forEach(item => {
item.open = !item.open;
this.openItem(item);
});
checkedList.forEach(item => {
this.changeChecked(item.commonId, item);
});
});
}
componentWillReceiveProps(nextProps, nextContext) {
this.updateData(nextProps.data);
}
componentDidMount() {
this.updateData(this.props.data);
}
render() {
const { list } = this.state;
const listComponent = list.map(item => <View key={"key-" + item.commonId}>{this.renderItem(item)}</View>);
return <View className={"cu-tree"}>{listComponent}</View>;
}
}
ClTree.options = {
addGlobalClass: true
};
ClTree.defaultProps = {
showCheck: false,
data: []
};