【问题标题】:Material-ui table row onClick bypass for checkbox selectMaterial-ui表格行onClick绕过复选框选择
【发布时间】:2019-06-29 02:17:35
【问题描述】:

我正在使用material-ui数据表进行排序。这在每一行都包含一个复选框。我已经让每一行都返回一个链接的点击。

但是,我不希望复选框充当单击,而是希望它充当复选框并将行添加到选中状态。但是当点击复选框时,会返回行链接。

我需要从行链接中排除该单元格,或者以某种方式排除复选框。

https://codesandbox.io/s/rlkv87vor4

这是我尝试过的逻辑:

点击处理程序

if (event.target.classList.contains('selectCheckbox')) {
  return console.log('checkbox select');
  } else {
  return console.log('row link');
}

在我的demo row link 中单击复选框时总是返回。

<TableCell padding="checkbox">
  <Checkbox className="selectCheckbox" checked={isSelected} />
</TableCell>

【问题讨论】:

    标签: javascript reactjs material-ui


    【解决方案1】:

    解决此问题的最直接方法是为复选框和行设置两个单独的handleClick 方法(例如handleCheckboxClickhandleRowClick)。

    handleCheckboxClick 中,您可以调用event.stopPropagation(); 以防止handleRowClick 被调用。

    所以EnhancedTable 的以下部分将从:

      handleClick = (event, id) => {
        if (event.target.classList.contains("selectCheckbox")) {
          console.log("checkbox select");
        } else {
          console.log("row link");
        }
    
        const { selected } = this.state;
        const selectedIndex = selected.indexOf(id);
        let newSelected = [];
    
        if (selectedIndex === -1) {
          newSelected = newSelected.concat(selected, id);
        } else if (selectedIndex === 0) {
          newSelected = newSelected.concat(selected.slice(1));
        } else if (selectedIndex === selected.length - 1) {
          newSelected = newSelected.concat(selected.slice(0, -1));
        } else if (selectedIndex > 0) {
          newSelected = newSelected.concat(
            selected.slice(0, selectedIndex),
            selected.slice(selectedIndex + 1)
          );
        }
    
        this.setState({ selected: newSelected });
      };
    ...
    <TableRow
      hover
      onClick={event => this.handleClick(event, n.id)}
      role="checkbox"
      aria-checked={isSelected}
      tabIndex={-1}
      key={n.id}
      selected={isSelected}
    >
      <TableCell className="selectCheckbox" padding="checkbox">
        <Checkbox
          onClick={event => this.handleClick(event, n.id)}
          className="selectCheckbox"
          checked={isSelected}
        />
      </TableCell>
    

    类似于以下内容:

      handleCheckboxClick = (event, id) => {
        event.stopPropagation();
        console.log("checkbox select");
        const { selected } = this.state;
        const selectedIndex = selected.indexOf(id);
        let newSelected = [];
    
        if (selectedIndex === -1) {
          newSelected = newSelected.concat(selected, id);
        } else if (selectedIndex === 0) {
          newSelected = newSelected.concat(selected.slice(1));
        } else if (selectedIndex === selected.length - 1) {
          newSelected = newSelected.concat(selected.slice(0, -1));
        } else if (selectedIndex > 0) {
          newSelected = newSelected.concat(
            selected.slice(0, selectedIndex),
            selected.slice(selectedIndex + 1)
          );
        }
    
        this.setState({ selected: newSelected });
      };
      handleRowClick = (event, id) => {
        console.log("row link");
      };
    ...
    <TableRow
      hover
      onClick={event => this.handleRowClick(event, n.id)}
      role="checkbox"
      aria-checked={isSelected}
      tabIndex={-1}
      key={n.id}
      selected={isSelected}
    >
      <TableCell className="selectCheckbox" padding="checkbox">
        <Checkbox
          onClick={event =>
            this.handleCheckboxClick(event, n.id)
          }
          className="selectCheckbox"
          checked={isSelected}
        />
    

    这是一个展示这种方法的 CodeSandbox:

    【讨论】:

    • @MalikBrahimi 我建议您创建自己的单独问题来演示如何重现您的问题。
    • 我发现了我的问题。我使用的是 onChange 而不是 onClick。你知道复选框之间的细微差别是什么吗?
    • @MalikBrahimi 该行正在响应点击事件。该行没有 onChange 事件,因此停止传播 Checkbox 的 onChange 事件不会影响点击事件是否传播到该行。
    • @MalikBrahimi 至于复选框事件之间的区别,在其他地方(例如stackoverflow.com/questions/5575338/…)解决。
    【解决方案2】:

    只需在复选框上添加 onClick 并调用 e.stopPropagation(); 以防止从复选框和行组件调用 onClick 两次!

    handleClick = (event, id) => {
        event.stopPropagation();
    
        const {selected} = this.state;
        const selectedIndex = selected.indexOf(id);
        let newSelected = [];
    
        if (selectedIndex === -1) {
          newSelected = newSelected.concat(selected, id);
        } else if (selectedIndex === 0) {
          newSelected = newSelected.concat(selected.slice(1));
        } else if (selectedIndex === selected.length - 1) {
          newSelected = newSelected.concat(selected.slice(0, -1));
        } else if (selectedIndex > 0) {
          newSelected = newSelected.concat(
            selected.slice(0, selectedIndex),
            selected.slice(selectedIndex + 1),
          );
        }
    
        this.setState({selected: newSelected});
      };
    
      <TableRow
                          hover
                          onKeyDown={event => this.handleKeyDown(event, n.id)}
                          role="checkbox"
                          aria-checked={isSelected}
                          tabIndex={-1}
                          key={n.id}
                          onClick={event => onMore(event, n.id)}
                          selected={isSelected}
                        >
    
                          <TableCell padding="checkbox">
                            <Checkbox color="primary" checked={isSelected}
                                      onClick={event => this.handleClick(event, n.id)}/>
                          </TableCell>
    </TableRow>
    

    【讨论】:

      【解决方案3】:

      所以这里有多个问题。

      1) className 不是 Checkbox API 的有效属性 https://material-ui.com/api/checkbox/#checkbox-api

      2) console.log(event.target) 表明实际点击发生在用于设置输入样式的 svg 标签上,而不是输入本身。因此,您也不能直接使用 inputProps={{className:"selectedCheckbox"}} 并从 classList 中捕获相同的内容

      你可以参考这个沙盒,看看如果你真的点击input : https://codesandbox.io/s/r7j4j638qn ,你如何得到想要的结果

      那么,一个可能的答案是修改Checkbox 组件的icon 属性并将其设置为具有指定类的自定义图标?然后它应该按预期工作。

      【讨论】:

      • 它仍然返回“行链接”而不是“复选框选择”,所以在我的情况下,它会将我带到另一个视图,而不是简单地选中复选框
      • 好吧,标题有点误导,我以为你担心点击会被绕过。让我再看看
      • className 是任何 DOM 元素的有效属性,您引用的文档表明“提供的任何其他属性都将传播到根元素(本机元素)。”
      • 我在事件目标中找不到类名。可能是一个错误?尝试了好的 ol' console.log() @RyanCogswell
      • className 被应用到最外层的span,它封装了复选框输入。创建的整体结构是&lt;span class="selectCheckbox and other classes"&gt;&lt;span&gt;&lt;svg/&gt;&lt;input type="checkbox"/&gt;&lt;/span&gt;&lt;/span&gt;
      猜你喜欢
      • 2021-05-08
      • 2020-11-18
      • 2023-03-16
      • 1970-01-01
      • 2020-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多