我想制作一种手风琴扩展面板:但是我不想有一个用于手风琴的组件,而没有一个用于单个扩展面板的组件。 我的目标是做这样的事情:
注意:我让它在另一个环境中工作,该环境使用来自特定框架的命名事件侦听器,但我想使其不使用框架,仅对ES6做出反应
df.xx.str.replace('\([^\)]*\)',' ')
Out[1249]:
0 y rfer
1 a ewq
Name: xx, dtype: object
因此,当我单击以展开第一个面板时,它会自我展开,并且当我单击第二个面板(并且uniqOpen标志处于打开状态)时,第二个面板将打开,第一个面板将关闭; 我在使用props和callbacks时遇到的问题是,我将不得不污染代码,并具有两个不同的组件来执行相同的操作。为什么不将一组ExpandingPanels嵌套在ExpandingGroup范围内?
这是我的ExpandingPanel代码:(忽略行,列和标签布局)
<ExpandingGroup id={'groupOne'} uniqOpen={true}>
<ExpandingPanel id={'panelOne'} />
<ExpandingPanel id={'panelTwo'} />
<ExpandingPanel id={'panelThree'}/>
<ExpandingPanel id={'panelFour'} />
</ExpandingGroup>
这是我的ExpandGroup代码:
import React from 'react';
import PropTypes from 'prop-types';
import Label from 'Base/Components/Label';
import Column from 'Base/Layouts/Column';
import Row from 'Base/Layouts/Row';
class ExpandPanel extends React.Component {
constructor(props) {
super(props);
this.id = this.props.id;
this.groupId = undefined;
this.anchorId = `anchor_${this.id}`;
this.panelId = `panel_${this.id}`;
this.colors = {
white: '#ffffff',
border: '#333333',
};
this.dim = {
minWidth: 40
}
this.styles = styles.bind(this);
this.getMaxHeight = getMaxHeight.bind(this);
this.handleUniq = handleUniq.bind(this);
this.handleClose = handleClose.bind(this);
this.handleOpenPanel = handleOpenPanel.bind(this);
this.handleToggle = handleToggle.bind(this);
this.checkExpanded = checkExpanded.bind(this);
this.setMyGroup = setMyGroup.bind(this);
this.state = {
isDrawerOpen: this.props.startOpen,
height: 'fit-content',
}
};
componentDidMount() {
setTimeout(() => {
this.setState({ height: this.getMaxHeight() });
});
let myInstance = document.getElementById(this.anchorId);
this.setMyGroup(myInstance.parentNode.parentNode.parentNode.id);
window.addEventListener('click', this.checkExpanded);
};
componentWillUnmount() {
window.removeEventListener('click', this.checkExpanded);
};
renderAnchor() {
return (
<Row id={this.anchorId} height={this.props.anchorHeight} onClick={ this.handleToggle } style={ this.styles('anchor') } >
{this.props.anchor}
</Row>
);
};
renderPanel() {
let height = this.props.autoHeight ? 'auto' : this.props.panelHeight;
return (
<Column id={this.panelId} height={height} style={ this.styles('panel') } >
{this.props.panel}
</Column>
)
};
render() {
return (
<div style={this.styles('margin')}>
<Column id={'ExpandPanel'} width={'100%'} height={'auto'} boxShadow={true} style={this.styles('root')}>
{ this.renderAnchor() }
{ this.renderPanel() }
</Column>
</div>
);
};
};
function setMyGroup(id) {
this.groupId = id;
}
function checkExpanded(click) {
let groupNode = click.path.filter( c => c && c.id && c.id.includes('ExpandGroup_') )[0];
let groupName = '';
if (groupNode && groupNode.id) groupName = groupNode.id;
else {
console.log('Not ExpandGroup click');
return null;
}
let isUniq = groupName.split('_');
isUniq = !!(isUniq[isUniq.length -1]);
if (isUniq) {
let isMyGroup = groupName === this.groupId;
if (!isMyGroup) return null;
let anchorNode = click.path.filter( c => c && c.id && c.id.includes('ExpandPanel') )[0];
let anchorName = anchorNode.firstChild.id;
if (isMyGroup && anchorName !== this.anchorId) this.handleClose();
} else return null;
};
function handleToggle(e) {
if (this.state.isDrawerOpen) this.handleClose();
else this.handleOpenPanel();
this.props.anchorClickCB({id: this.id, isDrawerOpen: !this.state.isDrawerOpen })
};
function handleClose() {
this.setState({isDrawerOpen: false}, this.props.onClose);
};
function handleOpenPanel() {
this.setState({isDrawerOpen: true});
};
function handleUniq({paramId, paramGroup}) {
let sameGroup = this.props.uniqGroup === paramGroup;
let otherId = this.id !== paramId;
if ( sameGroup && otherId ) this.handleClose();
};
function getMaxHeight() {
let panel = document.getElementById(this.panelId);
if (this.props.autoHeight && panel) {
return (panel.clientHeight + this.props.anchorHeight);
}
return (this.props.panelHeight + this.props.anchorHeight);
};
function styles(option) {
let rootMargin = this.props.showMargin && this.state.isDrawerOpen ? 10 : 0;
let panelHeightToogle = this.state.isDrawerOpen ? this.state.height : this.props.anchorHeight;
let anchorHeight = this.props.anchorHeight < this.dim.minWidth ? this.dim.minWidth : this.props.anchorHeight;
const styleObject = {
root: {
maxHeight: panelHeightToogle,
minHeight: anchorHeight,
transition: `max-height ${this.props.transition}s linear`,
overflow: 'hidden',
...this.props.style
},
anchor: {
cursor: 'pointer',
minHeight: anchorHeight,
...this.props.anchorStyle
},
panel: {
width: "100%",
overflow: 'auto',
...this.props.panelStyle
},
margin:{
marginBottom: rootMargin,
marginTop: rootMargin,
transition: `margin 0.15s linear`,
}
};
return styleObject[option]
};
ExpandPanel.defaultProps = {
id: 0,
uniqOpen: false,
uniqGroup: 'ExpandPanel',
anchor: <Row><Label text={'Default Anchor'}/></Row>,
anchorClickCB: ()=>{},
onClose: ()=>{},
anchorHeight: 50,
anchorStyle: {},
panel: <Column><Label text={'Default Panel'}/></Column>,
panelHeight: 200,
autoHeight: false,
panelStyle: {},
showMargin: false,
startOpen: false,
transition: 0.45,
style: {},
};
ExpandPanel.propTypes = {
id: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]),
uniqOpen: PropTypes.bool,
uniqGroup: PropTypes.string,
anchor: PropTypes.object,
anchorHeight: PropTypes.number,
anchorClickCB: PropTypes.func,
anchorStyle: PropTypes.object,
panel: PropTypes.object,
panelHeight: PropTypes.number,
autoHeight: PropTypes.bool,
panelStyle: PropTypes.object,
startOpen: PropTypes.bool,
transition: PropTypes.number,
style: PropTypes.object,
};
export default ExpandPanel;
这是电话:
import React from 'react';
import PropTypes from 'prop-types';
class ExpandGroup extends React.Component {
constructor(props) {
super(props);
this.id = `ExpandGroup_${this.props.id}_${this.props.uniqOpen}`;
};
render() {
return (
<div id={this.id}>
{this.props.children}
</div>
);
};
};
ExpandGroup.defaultProps = {
id: 'default',
uniqOpen: false,
};
ExpandGroup.propTypes = {
id: PropTypes.string,
uniqOpen: PropTypes.bool,
};
export default ExpandGroup;
答案 0 :(得分:0)
即使我不擅长克隆孩子,我还是使用@Cameron Downer的建议,但令我惊讶的是,它非常有效。 这是我的解决方案:
import random
def repeat(a, b):
nums = set()
count = 0
while len(nums) == count:
nums.add(random.randint(a, b))
count += 1
return list(nums)
和
import React from 'react';
import PropTypes from 'prop-types';
// import ExpandPanel from '../ExpandPanel';
let count = 0;
class ExpandGroup extends React.Component {
constructor(props) {
super(props);
this.id = `${this.props.id}_${count++}`;
this.state = {
openChildId: '',
};
this.styles = styles.bind(this);
this.updateOpenChildId = updateOpenChildId.bind(this);
this.panelPropsFix = panelPropsFix.bind(this);
this.checkStartOpen = checkStartOpen.bind(this);
};
render() {
return (
<div id={this.id} style={this.styles('root')}>
{this.panelPropsFix()}
</div>
);
};
};
function panelPropsFix() {
return React.Children.map(this.props.children,
(child, key) => {
let childClass = child.type.toString().split(' ')[1];
if (childClass === 'ExpandPanel') {
let childId = child.props.id;
return React.cloneElement(child, {
key: key,
startOpen: this.checkStartOpen(childId),
style: this.styles('child'),
openId: (this.props.singleOpen) ? this.state.openChildId : childId,
singleOpenCB: id => this.updateOpenChildId(id),
})
}
}
);
};
function checkStartOpen(childId) {
if (typeof this.props.openPanels === 'boolean') return this.props.openPanels;
else if (this.props.openPanels instanceof Array) {
return this.props.openPanels.includes(childId);
}
return false;
};
function updateOpenChildId(id) {
if (id === this.state.openChildId) {
this.setState({openChildId: ''});
} else {
this.setState({openChildId: id});
}
};
function styles(option) {
const styleObject = {
root: {
margin: this.props.margin,
padding: this.props.padding,
...this.props.style
},
child: {
...this.props.panelsStyle,
}
};
return styleObject[option]
};
ExpandGroup.defaultProps = {
id: 'ExpandGroup',
children: undefined,
singleOpen: false,
openPanels: false,
panelsStyle: {},
margin: 0,
padding: 0,
style: {},
};
ExpandGroup.propTypes = {
id: PropTypes.string,
// children: PropTypes.arrayOf(PropTypes.instanceOf(ExpandPanel)),
singleOpen: PropTypes.bool,
openPanels: PropTypes.oneOfType([ PropTypes.bool, PropTypes.array ]),
panelsStyle: PropTypes.object,
margin: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]),
padding: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]),
style: PropTypes.object,
};
export default ExpandGroup;
所以呼叫可以像这样:
import React from 'react';
import PropTypes from 'prop-types';
import Label from 'Base/Components/Label';
import Column from 'Base/Layouts/Column';
import Row from 'Base/Layouts/Row';
class ExpandPanel extends React.Component {
constructor(props) {
super(props);
this.id = this.props.id;
this.colors = {
white: '#ffffff',
border: '#333333',
};
this.dim = {
minWidth: 40
}
this.styles = styles.bind(this);
this.getMaxHeight = getMaxHeight.bind(this);
this.handleClose = handleClose.bind(this);
this.handleOpenPanel = handleOpenPanel.bind(this);
this.handleToggle = handleToggle.bind(this);
this.state = {
isDrawerOpen: this.props.startOpen,
height: 'fit-content',
}
};
componentDidMount() {
setTimeout(() => {
this.setState({ height: this.getMaxHeight() });
});
};
componentWillReceiveProps(nextProps) {
if (nextProps && nextProps.openId !== this.id)
this.handleClose();
};
renderAnchor() {
return (
<Row id={'anchor'} height={this.props.anchorHeight} boxShadow={this.props.boxShadow} onClick={ this.handleToggle } style={ this.styles('anchor') } >
{this.props.anchor}
</Row>
);
};
renderPanel() {
let height = this.props.autoHeight ? 'auto' : this.props.panelHeight;
return (
<Column id={'panel'} height={height} boxShadow={this.props.boxShadow} style={ this.styles('panel') } >
{this.props.panel}
</Column>
)
};
render() {
return (
<Column id={this.id} width={'100%'} height={'auto'} boxShadow={this.props.boxShadow} style={this.styles('root')}>
{ this.renderAnchor() }
{ this.renderPanel() }
</Column>
);
};
};
function handleToggle(e) {
if (this.state.isDrawerOpen) this.handleClose();
else this.handleOpenPanel();
this.props.singleOpenCB(this.id);
this.props.anchorClickCB({id: this.id, isDrawerOpen: !this.state.isDrawerOpen });
};
function handleClose() {
this.setState({isDrawerOpen: false}, this.props.onClose);
};
function handleOpenPanel() {
this.setState({isDrawerOpen: true}, this.props.onOpen);
};
function getMaxHeight() {
let panel = document.getElementById(this.panelId);
if (this.props.autoHeight && panel) {
return (panel.clientHeight + this.props.anchorHeight);
}
return (this.props.panelHeight + this.props.anchorHeight);
};
function styles(option) {
let rootMargin = this.props.showMargin && this.state.isDrawerOpen ? 10 : 0;
let panelHeightToogle = this.state.isDrawerOpen ? this.state.height : this.props.anchorHeight;
let anchorHeight = this.props.anchorHeight < this.dim.minWidth ? this.dim.minWidth : this.props.anchorHeight;
const styleObject = {
root: {
maxHeight: panelHeightToogle,
minHeight: anchorHeight,
transition: `max-height ${this.props.transition}s linear`,
overflow: 'hidden',
...this.props.style
},
anchor: {
cursor: 'pointer',
minHeight: anchorHeight,
...this.props.anchorStyle
},
panel: {
width: "100%",
overflow: 'auto',
...this.props.panelStyle
},
margin:{
marginBottom: rootMargin,
marginTop: rootMargin,
transition: `margin 0.15s linear`,
}
};
return styleObject[option]
};
ExpandPanel.defaultProps = {
id: 0,
anchor: <Row><Label text={'Default Anchor'}/></Row>,
anchorClickCB: ()=>{},
singleOpenCB: ()=>{}, // for ExpandGroup internal use
openId: '', // for ExpandGroup internal use
anchorHeight: 35,
anchorStyle: {},
panel: <Column><Label text={'Default Panel'}/></Column>,
onOpen: ()=>{},
onClose: ()=>{},
autoHeight: false,
panelHeight: 200,
panelStyle: {},
startOpen: false,
boxShadow: true,
transition: 0.45,
style: {},
};
ExpandPanel.propTypes = {
id: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]),
anchor: PropTypes.object,
anchorClickCB: PropTypes.func,
singleOpenCB: PropTypes.func, // for ExpandGroup internal use
openId: PropTypes.string, // for ExpandGroup internal use
anchorHeight: PropTypes.number,
anchorStyle: PropTypes.object,
panel: PropTypes.object,
onOpen: PropTypes.func,
onClose: PropTypes.func,
autoHeight: PropTypes.bool,
panelHeight: PropTypes.number,
panelStyle: PropTypes.object,
startOpen: PropTypes.bool,
boxShadow: PropTypes.bool,
transition: PropTypes.number,
style: PropTypes.object,
};
export default ExpandPanel;