【问题标题】:MaterialUI-Next Close drawer on children clickMaterial UI-Next 关闭子项点击抽屉
【发布时间】:2018-03-02 14:33:19
【问题描述】:

我正在运行 MaterialUI-Next 并且我已经尝试了抽屉的所有变体,但是当点击抽屉中的项目时我无法关闭它。我知道临时变体允许我这样做,但是当单击任何内容时它会关闭。我只需要在单击 ListItem 时关闭它。

在我的例子中,我在抽屉里有一个 ExpansionPanel,里面有 Lists 和 ListItems。单击扩展面板不应关闭抽屉,抽屉应保持打开状态,因为我还没有准备好离开。但是,当我单击抽屉中的 ListItem(它们包含 component="a" 项目)时,抽屉应该关闭,并且 component="a" 导航到它的 href。

我的代码非常基本和普通,实际上是来自MaterialUI-Next Drawers 的精确演示。他们还有一个测试代码的游乐场。但无论如何,这是我的一些相关代码

我的抽屉:

<Drawer
    variant="persistent" //I tried "temporary", and "permanent" as well
    elevation={16}
    anchor="right"
    open={this.state.open}
    // onClick={(open) => this.setState({ open: false })}
    // onKeyDown={(open) => this.setState({ open: false })}>
    <SystemMenu />
</Drawer>

存储在 SystemMenu 中的我的内容:

import React from 'react';
import { withStyles } from 'material-ui-next/styles';
import List, { ListItem, ListItemText } from 'material-ui-next/List';
import ExpansionPanel, { ExpansionPanelDetails, ExpansionPanelSummary } from 'material-ui-next/ExpansionPanel';
import ListSubheader from 'material-ui-next/List/ListSubheader';
import {ChevronDown} from 'mdi-material-ui';
import Grid from 'material-ui-next/Grid';
const OTHERPAGES = require('data/pages.js');
const systemMenuData = OTHERPAGES['systemMenuPagesItems'];

class SystemMenu extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            expanded: null,
        };
    }

    handleChange = panel => (event, expanded) => {
        this.setState({
            open: false,
            expanded: expanded ? panel : false,
        });
    };

    render() {
        const { expanded, open } = this.state;
        return (
            <div>
                <Grid
                    container>
                    <Grid item xs={12} style={{padding: 0}}>
                        <ListSubheader component="div">MENU ITEMS</ListSubheader>
                    </Grid>
                </Grid>
                <Grid
                    container>
                    <Grid item xs={12}>
                        <ExpansionPanel
                            expanded={expanded === 'panel1'}
                            onChange={this.handleChange('panel1')}>
                            <ExpansionPanelSummary
                                expandIcon={<ChevronDown />}>
                                Players
                            </ExpansionPanelSummary>
                            <ExpansionPanelDetails>
                                <List>
                                    <ListItem
                                        button
                                        component="a"
                                        href="/app/page1">
                                        <ListItemText primary="Page 1" />
                                    </ListItem>
                                    <ListItem
                                        button
                                        component="a"
                                        href="/app/page2">                                          
                                        <ListItemText primary="Page 2" />
                                    </ListItem>
                                    <ListItem
                                        button
                                        component="a"
                                        href="/app/page3">                                          
                                        <ListItemText primary="Page 3" />
                                    </ListItem>
                                </List>
                            </ExpansionPanelDetails>
                        </ExpansionPanel>
                    </Grid>
                </Grid>
            </div>
        );
    }
}

export default withStyles(styles)(SystemMenu);

我在其他帖子中读到,您可以使用道具将onKeyDown={(open) =&gt; this.setState({ open: false })} 传递给它的孩子。但是我是 React 的新手,对这个概念有一些问题。

基本上,我需要让 onKeyDown 为 ListItems 工作,而不是实际的抽屉。我可能需要也可能不需要将我的 Drawer 变体改回临时的 onKeyDown 属性才能工作。不太确定。

(记住上面的链接提供了一个测试代码的游乐场。比我尝试为 React 构建 jFiddle 好多了)

编辑

我想出了一个不同的方法,但不是我最喜欢的。

通过将 SystemMenu 中的内容移动到 Menu.js 文件(我的 Drawer 导入、函数和状态所在的位置),我能够创建一个带有超时的 handleClose 函数,以便它关闭。这是函数:

handleClose = () => {
    if (!this.state.open) {
        return;
    }
    this.timeout = setTimeout(() => {
        this.setState({ open: false });
        this.setState({ expanded: null });
    });
};

这需要持久变体和handleOpen() 函数来保持抽屉打开,直到我单击具有handleClose() 函数的列表。所以,我的抽屉现在是这样的

<Drawer
    variant="persistent"
    elevation={16}
    anchor="right"
    open={this.state.open}
    onClick={() => { this.handleOpen(); }}>
    ...
       My System Menu code in here, not too happy about this part. :(
    ...
</Drawer>

接下来,在包含扩展面板和列表的系统菜单代码中,我将handleClose() 函数添加到列表中,它可以导航以及关闭抽屉和扩展面板。像这样:

<List 
    className="quickpanel-navigation"
    onClick={() => { this.handleClose(); }}>
    .... ListItems code here ....
</List>

这是一个好的方法,但我更愿意将 SystemMenu 代码放在另一个文件中并导入到这个文件中,并使用道具从 SystemMenu.js 文件中操作 Menu.js 文件中的关闭函数。如果还有其他人想继续帮助我,我将不胜感激。

【问题讨论】:

    标签: reactjs material-ui


    【解决方案1】:

    demo 中,他们将所有 ListItems 包装在处理关闭抽屉的 div 中:

    <div
      tabIndex={0}
      role="button"
      onClick={this.toggleDrawer('left', false)}
      onKeyDown={this.toggleDrawer('left', false)}
    >
      {sideList}
    </div>
    

    在这段代码中,toggleDrawer 是一个设置用于 Drawer 的 open 属性的状态的函数。因此,当按下某个键或在 List 的其中一个子项中发生单击时,事件会冒泡到这些处理程序(只要不使用 event.stopPropagation())并且状态会更改。

    在您的代码中,您不希望展开器的单击关闭抽屉,因此您必须以不同的方式处理这些事件。

    您可以将onClick 处理程序添加到列表中:

    <ExpansionPanelDetails>
        <List onClick={ () => { /* close the drawer here */ } }>
            <ListItem
                button
                component="a"
                href="/app/page1">
                <ListItemText primary="Page 1" />
            </ListItem>
            <ListItem
                button
                component="a"
                href="/app/page2">                                          
                <ListItemText primary="Page 2" />
            </ListItem>
            <ListItem
                button
                component="a"
                href="/app/page3">                                          
                <ListItemText primary="Page 3" />
            </ListItem>
        </List>
    </ExpansionPanelDetails>
    

    然后,当单击 ListItems 时,事件将冒泡到 List 的处理程序,该处理程序设置状态,关闭抽屉。

    根据您的代码结构,您可能需要修改 Drawer 的实现以将函数传递给您的 SystemMenu 组件,以便其 List 上的点击处理程序可以设置其父级的状态,因为 this.setState 会影响this 的状态,这是该组件的当前实例。它不会设置抽屉的状态。

    更新:

    根据您的 cmets,我正在添加这一点。

    在您的 SystemMenu 组件中: - 接受名为closeDrawer 的道具。 - 使用这个函数,来自 props,作为 List 上的 onClick 处理程序

    • 在您的菜单组件中:
    • 添加一个关闭抽屉的函数,我们暂时称之为closeDrawer
    • 渲染 SystemMenu 时,将 this.closeDrawer 传递为 `closeDrawer
         <SystemMenu closeDrawer={this.closeDrawer} ...>
    

    这是从子 SystemMenu 中更改父组件 Menu 的本地状态的一种方法。

    【讨论】:

    • 对不起,我忘了提到 SystemMenu 是在一个单独的文件中,我正在导入到包含抽屉的文件中。它无法识别 ToggleDrawer 函数,因为它是在单独的文件中声明的。
    • 以及Drawer组件,它也没有在SystemMenu文件中声明,但它是包含Drawer的Menu.js。这就是为什么我认为 props 是正确的方法。这不就是props应该做的吗?操作存在于文件之外的函数?在它的父级中?
    • 我想出了一种让它工作的方法,但我必须在菜单文件中包含 SystemMenu 代码,这样我才能访问导入和函数。请参阅我的编辑。为你的工作+1,因为你让我的齿轮转动了。但是,我的问题仍然存在。我宁愿能够从另一个文件中的子代码中操作抽屉
    • 我知道它们位于不同的文件中,这就是为什么我写了你需要从定义 Drawer 的地方向 SystemMenu 传递一个函数的原因。在呈现 Drawer 的类中创建一个 closeDrawer 函数,并在 SystemMenu 组件中公开一个可以接受它的道具。然后在 SystemMenu 组件中,将其用作 List 的点击处理程序。
    • @LOTUSMS 看到我拼出来的更新答案。
    【解决方案2】:

    通过PaperProps将关闭处理程序放在MuiPaper上:

    const handleClose = () => console.log('closing drawer');
    
    const MyDrawer = () => <Drawer PaperProps={{onClick: handleClose}} />
    

    当点击抽屉内的任何地方时,这将关闭抽屉。

    【讨论】:

      【解决方案3】:

      假设你的 Drawer 在一个类组件中,你会做这样的事情来从一个子组件中关闭它。

      class MyComponent extends React.Component {
          constructor(props){
              super(props)
              this.state = {
                  open: false,
              }
          }
      
          closeDrawer = () => this.setState({ open: false })
      
          render() {            
              return (
                  <Drawer
                      elevation={16}
                      anchor="right"
                      open={this.state.open}
                      onKeyDown={this.closeDrawer}
                  >
                      <SystemMenu 
                          closeDrawer={this.closeDrawer}
                      />
                  </Drawer>
              )
          }
      }
      

      然后您可以从SystemMenu 中访问this.props.closeDrawer。听起来您想为列表项添加到 onClick 处理程序:

      <ListItem
          button
          component="a"
          href="/app/page1"
          onClick={this.props.closeDrawer}
      >
          <ListItemText primary="Page 1" />
      </ListItem>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-23
        • 2020-07-07
        • 2018-09-28
        • 1970-01-01
        • 2020-12-26
        • 2014-04-02
        • 1970-01-01
        相关资源
        最近更新 更多