我创建了一个用于导航的反应组件树。 您可以在下面的代码中看到它。
let navConfigData = {
isDashboardVisible: true,
tierOneLinks: [
{
name: "First Page",
iconName: "star",
iconAbbreviation: "FP",
tierTwoItems: [
{
name: "Tier 2 Page",
iconName: "star",
iconAbbreviation: "FP",
tierThreeItems: [
{
name: "Tier 3 Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Tier 2 sec Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Second Page",
iconName: "",
iconAbbreviation: "SP",
path: "#"
},
{
name: "Third Page",
iconAbbreviation: "TP",
path: "#",
tierTwoItems: [
{
name: "Tier 2 Page",
iconName: "star",
iconAbbreviation: "FP",
tierThreeItems: [
{
name: "Tier 3 Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Tier 2 sec Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Fourth Page",
iconName: "send",
iconAbbreviation: "FO",
path: "#"
}
],
supportLinks: [
{
name: "First Support Page",
iconName: "settings",
iconAbbreviation: "FI",
path: "#"
},
{
name: "Second Support Page",
iconName: "security",
iconAbbreviation: "SE",
path: "#"
},
{
name: "Third Support Page",
iconName: "help",
iconAbbreviation: "TH",
path: "#"
}
]
};
class NavigationDrawerTierThree extends React.Component {
onClick = evt => {
this.props.onSelect(this.props.tierThree.name);
};
render() {
const { tierThree, selectedTierThreeLink } = this.props;
debugger;
return (
<a
className="mdc-list-item my-nav-drawer__tier-three"
onClick={this.onClick}
>
<span className="my-nav-drawer__tier-two-label">
{tierThree.name}
</span>
</a>
);
}
}
class NavigationDrawerTierTwo extends React.Component {
// static propTypes = {
// tierTwo: object.isRequired,
// showNavIcon: bool,
// onSelect: func.isRequired,
// selectedTierTwoLink: string.isRequired
// };
state = { tierTwoIsExpanded: false };
onClick = evt => {
debugger;
this.props.onSelect(this.props.tierTwo.name, "tier2");
const { tierTwoIsExpanded } = this.state;
this.setState({ tierTwoIsExpanded: !tierTwoIsExpanded });
};
getArrowIcon = () => {
return this.state.tierTwoIsExpanded ? (
<span class="material-icons cdk-nav-drawer__tier-two-icon">></span>
) : (
<span class="material-icons cdk-nav-drawer__tier-two-icon">
^
</span>
);
};
getAnchorClassBasedOnTier = () => {
return this.props.showNavIcon
? "cdk-nav-drawer__tier-two"
: "cdk-nav-drawer__tier-three";
};
getLabelClassBasedOnTier = () => {
return this.props.showNavIcon
? "cdk-nav-drawer__tier-two-label"
: "cdk-nav-drawer__tier-three-label";
};
render() {
const { tierTwo, showNavIcon, selectedTierTwoLink } = this.props;
const { tierTwoIsExpanded } = this.state;
debugger;
return (
<div>
<a
className="mdc-list-item my-nav-drawer__tier-two"
onClick={this.onClick}
>
{showNavIcon && this.getArrowIcon()}
<span className="my-nav-drawer__tier-two-label">
{tierTwo.name}
</span>
</a>
{tierTwoIsExpanded && this.props.children}
</div>
);
}
}
class NavigationDrawerTierOneAnchor extends React.Component{
// static propTypes = {
// tierOne: object.isRequired,
// onSelect: func.isRequired,
// selectedTierOneLink: string.isRequired
// };
// state = { tierIsExpanded: false };
onClick = evt => {
this.props.onSelect(this.props.tierOne.name, "tier1");
// const { tierIsExpanded } = this.state;
// this.setState({ tierIsExpanded: !tierIsExpanded });
};
render(){
const { tierOne, selectedTierOneLink, expanded } = this.props;
return(
<div>
<a
className="mdc-list-item my-nav-drawer__tier-one"
href={tierOne.path}
onClick={this.onClick}
ref={a => {
this.anchor = a;
}}
>
<span className="cdk-nav-drawer__tier-one-label">
{tierOne.name}
</span>
</a>
{expanded && this.props.children}
</div>
);
}
}
class NavigationDrawerAppTiers extends React.Component {
// static propTypes = {
// tierOneArray: array.isRequired,
// onToggleExpand: func.isRequired,
// onSelect: func.isRequired,
// selectedTierOneLink: string.isRequired,
// selectedTierTwoLink: string.isRequired,
// selectedTierThreeLink: string.isRequired,
// expandedTierOneName: string.isRequired
// };
render(){
const { tierOneArray, onSelect, selectedTierOneLink, selectedTierTwoLink, selectedTierThreeLink, expandedTierOneName } = this.props;
return (
<div className="mdc-drawer__content my-nav-drawer__app-tiers">
<nav className="mdc-list">
{tierOneArray.map((tierOneLink, index) => (
<NavigationDrawerTierOneAnchor
tierOne={tierOneLink}
onSelect={onSelect}
key={index}
expanded={tierOneLink.name === this.props.expandedTierOneName}
selectedTierOneLink={selectedTierOneLink}
>
{(tierOneLink.tierTwoItems || []).map((tierTwoItem, index) => (
<NavigationDrawerTierTwo
tierTwo={tierTwoItem}
onSelect={onSelect}
selectedTierTwoLink={selectedTierTwoLink}
showNavIcon={
(tierTwoItem.tierThreeItems &&
tierTwoItem.tierThreeItems.length > 0) ||
false
}
>
{(tierTwoItem.tierThreeItems || []).map(
(tierThreeItem, index) => (
<NavigationDrawerTierThree
tierThree={tierThreeItem}
onSelect={onSelect}
selectedTierThreeLink={selectedTierThreeLink}
/>
)
)}
</NavigationDrawerTierTwo>
))}
</NavigationDrawerTierOneAnchor>
))}
</nav>
</div>
);
}
}
class NavigationDrawer extends React.Component {
// static propTypes = {
// navConfig: object.isRequired
// };
state = {
isDrawerCollapsed: false,
selectedTierOneLink: "",
selectedTierTwoLink: "",
selectedTierThreeLink: "",
expandedTierOneName: ""
};
onSelect = (selectedLinkName, selectedTier) => {
if(selectedTier == "tier1"){
if (selectedLinkName === this.state.selectedTierOneLink) {
// User clicked on the same link again
this.setState(state => ({
expandedTierOneName: state.expandedTierOneName?"":selectedLinkName
}))
} else {
this.setState(state=>({
expandedTierOneName:selectedLinkName
}))
}
this.setState(state => ({ selectedTierOneLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
} else if (selectedTier == "tier2"){
this.setState(state => ({ selectedTierTwoLink: selectedLinkName }));
this.setState(state => ({ selectedTierThreeLink: "" }));
} else {
this.setState(state => ({ selectedTierThreeLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
}
};
render(){
const { navConfig } = this.props;
return(
<nav className="mdc-drawer mdc-drawer--permanent mdc-typography my-nav-drawer">
<div className="my-nav-drawer__links">
<NavigationDrawerAppTiers
tierOneArray={navConfig.tierOneLinks}
onSelect={this.onSelect}
selectedTierOneLink={this.state.selectedTierOneLink}
selectedTierTwoLink={this.state.selectedTierTwoLink}
selectedTierThreeLink={this.state.selectedTierThreeLink}
expandedTierOneName={this.state.expandedTierOneName}
/>
</div>
</nav>
);
}
}
React.render(
<NavigationDrawer navConfig={navConfigData}/>,
document.body
);
该组件最多可达三个级别,我不希望它目前通过递归实现。
我正在寻找一种行为,在从另一个父树中选择任何子节点后关闭先前打开的父树节点。
要从Codepen示例中详细解释,我需要有关以下方案的帮助。
目前,如果未选择子项,则只能切换一个父节点。
我需要帮助才能实现以下方案。
如果从第三页中没有选择子项,则再次单击第三页,则应折叠所有打开的父节点(第一页和第三页)。
有人可以帮我修改码头。
在代码抛出下,未定义initialState
class NavigationDrawer extends React.Component {
static propTypes = {
navConfig: object.isRequired
};
initialState = this.props.navConfig.tierOneLinks.reduce((acc, { name }) => {
acc[name] = false;
return acc;
}, {});
state = {
expanded: initialState,
isDrawerCollapsed: false,
selectedTierOneLink: "",
selectedTierTwoLink: "",
selectedTierThreeLink: "",
expandedTierOneName: ""
};
onSelect = (selectedLinkName, selectedTier) => {
if(selectedTier == "tier1"){
if (selectedLinkName === this.state.selectedTierOneLink) {
// User clicked on the same link again
this.setState(state => ({
expandedTierOneName: state.expandedTierOneName?"":selectedLinkName
}))
} else {
this.setState(state=>({
expandedTierOneName:selectedLinkName
}))
}
this.setState(state => ({ selectedTierOneLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
} else if (selectedTier == "tier2"){
this.setState(state => ({ selectedTierTwoLink: selectedLinkName }));
this.setState(state => ({ selectedTierThreeLink: "" }));
} else {
this.setState(state => ({ selectedTierThreeLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
}
};
render(){
const { navConfig } = this.props;
return(
<nav className="mdc-drawer mdc-drawer--permanent mdc-typography my-nav-drawer">
<div className="my-nav-drawer__links">
<NavigationDrawerAppTiers
tierOneArray={navConfig.tierOneLinks}
onSelect={this.onSelect}
selectedTierOneLink={this.state.selectedTierOneLink}
selectedTierTwoLink={this.state.selectedTierTwoLink}
selectedTierThreeLink={this.state.selectedTierThreeLink}
expandedTierOneName={this.state.expandedTierOneName}
/>
</div>
</nav>
);
}
}