首页 > 解决方案 > 如何使用“onclick”事件更改 ListItem 元素的样式?

问题描述

我的目标是当我单击 ListItem 时,它应该更改background-colorand text: "line-through"。然后,如果我再次单击,这些更改应该被取消。
但这对我来说发生得很奇怪。我只是不明白为什么只有在单击窗口的任何位置后才会ListItem更改?background-color为什么只有在我将指针移到元素之外之后,ListItem 中的文本才会被划掉

const styles = () => ({
  listItem: {
    borderRadius: "1em"
  },

  listItemDone: {
    borderRadius: "1em",
    backgroundColor: "#F6F6E8",
    textDecoration: "line-through"
  },

  iconButton: {
    padding: 5
  },

  important: {
    color: "#00ACE9",
    fontWeight: "bold"
  }
});

class TodoListItem extends Component {
  state = {
    done: false
  };

  onClickItem = () => {
    this.setState({
      done: !this.state.done
    });
  };

  render() {
    const { label, important = false, classes } = this.props;
    const { done } = this.state;

    return (
      <ListItem
        onClick={this.onClickItem}
        className={done ? classes.listItemDone : classes.listItem}
        button
        divider
      >
        <ListItemText
          primary={label}
          classes={{ primary: important ? classes.important : "" }}
        />
      </ListItem>
    );
  }
}

编辑 v8ojkj2qzy

标签: reactjsmaterial-ui

解决方案


每当您尝试覆盖 Material-UI 样式并且它没有像您期望的那样工作时,最好的资源是源代码。这是ListItem源代码的 URL:https ://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/ListItem/ListItem.js 。在大多数情况下,您只需要查看styles源文件顶部附近的变量。

下面我复制了styles处理backgroundColorand的所有变量部分textDecoration

export const styles = theme => ({
  /* Styles applied to the (normally root) `component` element. May be wrapped by a `container`. */
  root: {
    textDecoration: 'none',
    '&$selected, &$selected:hover, &$selected:focus': {
      backgroundColor: theme.palette.action.selected,
    },
  },
  /* Styles applied to the inner `component` element if `button={true}`. */
  button: {
    transition: theme.transitions.create('background-color', {
      duration: theme.transitions.duration.shortest,
    }),
    '&:hover': {
      textDecoration: 'none',
      backgroundColor: theme.palette.action.hover,
      // Reset on touch devices, it doesn't add specificity
      '@media (hover: none)': {
        backgroundColor: 'transparent',
      },
    },
    '&:focus': {
      backgroundColor: theme.palette.action.hover,
    },
  },
  /* Styles applied to the root element if `selected={true}`. */
  selected: {},
});

导致困难的主要样式是button悬停和焦点样式。为了在不诉诸“!important”的情况下成功覆盖这些内容,您需要具有适当的 CSS 特异性。

以下似乎可以解决问题:

  listItemDone: {
    borderRadius: "1em",
    "&,&:focus,&:hover": {
      backgroundColor: "#F6F6E8",
      textDecoration: "line-through"
    }
  },

但是,以上内容可以防止对“完成”项目产生任何悬停效果,因此您可能想要做更多类似的事情:

  listItemDone: {
    borderRadius: "1em",
    "&,&:focus": {
      backgroundColor: "#F6F6E8",
      textDecoration: "line-through"
    },
    "&:hover": {
      textDecoration: "line-through"
    }
  },

这允许已完成项目的悬停背景颜色仍然是theme.palette.action.hover. 如果您希望已完成项目的悬停颜色不同,则可以与 textDecoration 一起显式指定它。

还有一个细节需要注意。如果单击列表项使其处于“完成”状态,然后再次单击它,它将不再处于“完成”状态,但会button应用焦点样式。为了删除该焦点样式,您还需要以下内容:

  listItem: {
    borderRadius: "1em",
    "&,&:focus": {
      backgroundColor: theme.palette.background.paper // or whatever color you want this to be
    }
  },

这是我修改后的沙箱版本:

编辑 5kv3j6r1xn


推荐阅读