我非常喜欢React中的内联CSS模式,并决定使用它。

但是,你不能使用:hover和类似的选择器。那么,在使用内联CSS样式时实现高亮悬停的最佳方法是什么呢?

#reactjs的一个建议是有一个Clickable组件,并像这样使用它:

<Clickable>
    <Link />
</Clickable>

Clickable有一个悬停状态,并将其作为道具传递给链接。然而,Clickable(我实现它的方式)将链接包装在一个div中,以便它可以设置onMouseEnter和onMouseLeave。这让事情变得有点复杂(例如,在div中包装的span与span的行为不同)。

有没有更简单的方法?


当前回答

我最近也遇到了同样的情况。这是我的一个非常简单的解决方案,使用一个自定义钩子,如果元素悬停或不悬停则返回。

export const useOnHover = (ref: React.RefObject) => {
    const [hovered, setHovered] = React.useState(false);

    const mouseEntered = React.useCallback(() => {
        setHovered(true);
    }, [ref.current]);

    const mouseLeft = React.useCallback(() => {
        setHovered(false);
    }, [ref.current]);

    React.useEffect(() => {
        if (!ref.current) return;

        ref.current.addEventListener("mouseenter", mouseEntered);
        ref.current.addEventListener("mouseleave", mouseLeft);

        return () => {
            if (!ref.current) return;
            ref.current.removeEventListener("mouseenter", mouseEntered);
            ref.current.removeEventListener("mouseleave", mouseLeft);
        };
    }, [ref.current]);

    return hovered;
};

现在你可以像这样在任何元素上使用它:

const Button = (props) => {
    const buttonRef = React.useRef(null);

    const buttonHovered = useOnHover(buttonRef);
    return (
        <div
            ref={buttonRef}
            style={{
                //your styles
                backgroundColor: "red",
                filter: buttonHovered ? "saturate(100%)" : "saturate(50%)",
            }}
        >
            {props.title}
        </div>
    );
};

其他回答

您可以使用css模块作为替代方案,另外还可以使用react-css-modules进行类名映射。

这样你就可以像下面这样导入你的样式,并在你的组件中使用正常的css范围:

import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css';

class Table extends React.Component {
    render () {
        return <div styleName='table'>
            <div styleName='row'>
                <div styleName='cell'>A0</div>
                <div styleName='cell'>B0</div>
            </div>
        </div>;
    }
}

export default CSSModules(Table, styles);

下面是一个webpack css模块的例子

<Hoverable hoverStyle={styles.linkHover}>
  <a href="https://example.com" style={styles.link}>
    Go
  </a>
</Hoverable>

其中Hoverable定义为:

function Hoverable(props) {
  const [hover, setHover] = useState(false);

  const child = Children.only(props.children);

  const onHoverChange = useCallback(
    e => {
      const name = e.type === "mouseenter" ? "onMouseEnter" : "onMouseLeave";
      setHover(!hover);
      if (child.props[name]) {
        child.props[name](e);
      }
    },
    [setHover, hover, child]
  );

  return React.cloneElement(child, {
    onMouseEnter: onHoverChange,
    onMouseLeave: onHoverChange,
    style: Object.assign({}, child.props.style, hover ? props.hoverStyle : {})
  });
}

我也有同样的情况。非常喜欢在组件中保持样式的模式,但悬停状态似乎是最后一个障碍。

我所做的是写一个mixin,你可以添加到你的组件,需要悬停状态。 这个mixin将为组件的状态添加一个新的悬停属性。如果用户将鼠标悬停在组件的主DOM节点上,它将被设置为true;如果用户离开元素,它将被设置为false。

现在在你的组件渲染函数中,你可以这样做:

<button style={m(
     this.styles.container,
     this.state.hovered && this.styles.hover,
)}>{this.props.children}</button>

现在,每当悬浮状态的状态发生变化时,组件将重新呈现。

我还为此创建了一个沙盒回购,我自己用它来测试这些模式中的一些。如果您想查看我的实现示例,请查看它。

https://github.com/Sitebase/cssinjs/tree/feature-interaction-mixin

onMouseOver和onMouseLeave with setState起初似乎对我来说有点开销-但这就是react的工作方式,对我来说这似乎是最简单和最干净的解决方案。

例如,呈现一个主题CSS服务器端也是一个很好的解决方案,可以使react组件更干净。

如果你不需要将动态样式附加到元素(例如主题),你就不应该使用内联样式,而应该使用CSS类。

这是一个传统的html/css规则,以保持html/ JSX干净简单。

你可以使用镭——它是一个开源工具,可以在ReactJS中使用内联样式。它恰好添加了您需要的选择器。非常受欢迎,看看npm上的镭