【问题标题】:Inline CSS styles in React: how to implement a:hover?React 中的内联 CSS 样式:如何实现 a:hover?
【发布时间】:2015-04-06 13:31:36
【问题描述】:

我非常喜欢inline CSS pattern in React 并决定使用它。

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

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

<Clickable>
    <Link />
</Clickable>

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

有没有更简单的方法?

【问题讨论】:

  • 你是绝对正确的 - 使用内联样式模拟 :hover 等选择器的唯一方法是使用 onMouseEnteronMouseLeave。关于它的确切实施 - 这完全取决于你。查看您的具体示例,为什么不将 &lt;Clickable/&gt; 包装器设为 span
  • 我建议使用外部样式表和 ExtractText Webpack 插件,如果您希望使用 ServerRender,这将帮助您更长时间地运行,否则您可以尝试 Radium github.com/FormidableLabs/radium
  • 目前 Styled Component 是在 react 中模拟 css/scss 的所有可能性的最佳解决方案。

标签: reactjs


【解决方案1】:

我认为 onMouseEnter 和 onMouseLeave 是可行的方法,但我认为不需要额外的包装器组件。以下是我的实现方式:

var Link = React.createClass({
  getInitialState: function(){
    return {hover: false}
  },
  toggleHover: function(){
    this.setState({hover: !this.state.hover})
  },
  render: function() {
    var linkStyle;
    if (this.state.hover) {
      linkStyle = {backgroundColor: 'red'}
    } else {
      linkStyle = {backgroundColor: 'blue'}
    }
    return(
      <div>
        <a style={linkStyle} onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>Link</a>
      </div>
    )
}

然后您可以使用悬停状态(真/假)来更改链接的样式。

【讨论】:

  • 这似乎涵盖了:hover,但不包括:focus
  • @AdamTuttle react 有一个 onFocus 事件;所以你可以为:focus:hover 做同样的事情,除了需要onMouseEnteronMouseLeave 你只需要onFocus
  • 请注意,此方法强制在主线程上执行,而典型的 CSS 事件处理效率更高。
【解决方案2】:

聚会迟到了,但有解决办法。您可以使用“&”来定义悬停第 n 个子等的样式:

day: {
    display: "flex",
    flex: "1",
    justifyContent: "center",
    alignItems: "center",
    width: "50px",
    height: "50px",
    transition: "all 0.2s",
    borderLeft: "solid 1px #cccccc",

    "&:hover": {
      background: "#efefef"
    },
    "&:last-child": {
      borderRight: "solid 1px #cccccc"
    }
},

【讨论】:

  • 这不是一个解决方案,问题是如何使用 INLINE css,而不是使用单独的样式表。
  • 老兄,仔细看看。这是内联样式。
  • 这不适用于 React。你需要一个额外的库,比如 styled-components。
  • 它不适用于内联样式,这个例子会带来混乱。如果它确实有效,请提供一个完整组件的更好示例。
  • 这不仅仅在 React 上工作,在 codesandbox.io/s/zealous-roentgen-yo57x 上测试
【解决方案3】:

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

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

现在在您的组件渲染函数中,您可以执行以下操作:

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

现在,每当hovered 状态的状态发生变化时,组件都会重新渲染。

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

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

【讨论】:

  • 不是长期运行的好解决方案,Radium 将是更好的选择或使用外部样式表
  • @abhirathore2006 Radium 的工作方式相同,问题是如何在不使用外部样式表的情况下做到这一点
  • 使用普通扩展运算符不是更有意义吗?
  • 上述m 是什么?
【解决方案4】:

您可以使用 Radium - 它是一个用于 ReactJS 内联样式的开源工具。它准确地添加了您需要的选择器。很受欢迎,看看-Radium on npm

【讨论】:

  • 我刚看到这篇文章,您将如何在以下情况下实现 Radium? module.exports = React.createClass({ displayName: 'App',})
  • @Rkayat 您可以将其包装为module.exports = Radium(React.createClass({ displayName: 'App',})) 或将类分配给一个值并在其上方添加@Radium 装饰器,因为文档提到github.com/FormidableLabs/radium#usage
  • 还有一个很棒的东西叫做 CSS ;)
【解决方案5】:

这是我使用 React Hooks 的解决方案。它结合了扩展运算符和三元运算符。

style.js

export default {
  normal:{
    background: 'purple',
    color: '#ffffff'
  },
  hover: {
    background: 'red'
  }
}

Button.js

import React, {useState} from 'react';
import style from './style.js'

function Button(){

  const [hover, setHover] = useState(false);

  return(
    <button
      onMouseEnter={()=>{
        setHover(true);
      }}
      onMouseLeave={()=>{
        setHover(false);
      }}
      style={{
        ...style.normal,
        ...(hover ? style.hover : null)
      }}>

        MyButtonText

    </button>
  )
}

【讨论】:

  • 我喜欢有创造力的人如何使用这些类型的东西,你可能可以使用像 const {onMouseEnter, onMouseLeave, styles } = useHoverStyle(style.hover) 这样的自定义钩子让这个更干净、更可重用由于缺乏对悬停状态的内联样式支持,因此依赖于如此复杂的 JS ?
【解决方案6】:

完整的 CSS 支持正是如此庞大的 CSSinJS 库的原因,为了有效地做到这一点,您需要生成实际的 CSS,而不是内联样式。此外,内联样式在更大的系统中的反应要慢得多。免责声明 - 我维护JSS

【讨论】:

  • 是什么让它变慢了?
  • @ICW 因为涉及到JS。
【解决方案7】:

制作Style It——部分原因——因为这个原因(其他人不同意其他库/语法的实现以及内联样式缺乏对属性值前缀的支持)。相信我们应该能够简单地用 JavaScript 编写 CSS 并拥有完全自包含的组件 HTML-CSS-JS。有了 ES5 / ES6 模板字符串,我们现在可以而且它也可以很漂亮! :)

npm install style-it --save

函数语法 (JSFIDDLE)

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return Style.it(`
      .intro:hover {
        color: red;
      }
    `,
      <p className="intro">CSS-in-JS made simple -- just Style It.</p>
    );
  }
}

export default Intro;

JSX 语法 (JSFIDDLE)

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return (
      <Style>
      {`
        .intro:hover {
          color: red;
        }
      `}

        <p className="intro">CSS-in-JS made simple -- just Style It.</p>
      </Style>
    );
  }
}

export default Intro;

【讨论】:

  • 我在 JSX 语法示例中注意到,JSFiddle 链接具有正确的代码,但此处显示的示例在样式结束标记后缺少右括号,并且缩进可能是由于缺少括号而关闭.
【解决方案8】:

添加到Jonathan's answer,这里是涵盖焦点和活动状态的事件,以及使用onMouseOver而不是onMouseEnter,因为如果您在目标事件中有任何子元素,后者不会冒泡正在应用于。

var Link = React.createClass({

  getInitialState: function(){
    return {hover: false, active: false, focus: false}
  },

  toggleHover: function(){
    this.setState({hover: !this.state.hover})
  },

  toggleActive: function(){
    this.setState({active: !this.state.active})
  },

  toggleFocus: function(){
    this.setState({focus: !this.state.focus})
  },

  render: function() {
    var linkStyle;
    if (this.state.hover) {
      linkStyle = {backgroundColor: 'red'}
    } else if (this.state.active) {
      linkStyle = {backgroundColor: 'blue'}
    } else if (this.state.focus) {
      linkStyle = {backgroundColor: 'purple'}
    } 

    return(
      <div>
        <a style={linkStyle} 
          onMouseOver={this.toggleHover} 
          onMouseOut={this.toggleHover} 
          onMouseUp={this.toggleActive} 
          onMouseDown={this.toggleActive} 
          onFocus={this.toggleFocus}> 
          Link 
        </a>
      </div>
    )
  }

【讨论】:

  • 关于可访问性的选项卡交互怎么样?我认为这只是一种解决方法。
【解决方案9】:

如果你使用带有 Typescript 的 React,请查看 Typestyle

以下是 :hover 的示例代码

import {style} from "typestyle";

/** convert a style object to a CSS class name */
const niceColors = style({
  transition: 'color .2s',
  color: 'blue',
  $nest: {
    '&:hover': {
      color: 'red'
    }
  }
});

<h1 className={niceColors}>Hello world</h1>

【讨论】:

    【解决方案10】:

    关于styled-componentsreact-router v4,您可以这样做:

    import {NavLink} from 'react-router-dom'
    
    const Link = styled(NavLink)`     
      background: blue;
    
      &:hover {
        color: white;
      }
    `
    
    ...
    <Clickable><Link to="/somewhere">somewhere</Link></Clickable>
    

    【讨论】:

      【解决方案11】:

      简单的方法是使用三元运算符

      var Link = React.createClass({
        getInitialState: function(){
          return {hover: false}
        },
        toggleHover: function(){
          this.setState({hover: !this.state.hover})
        },
        render: function() {
          var linkStyle;
          if (this.state.hover) {
            linkStyle = {backgroundColor: 'red'}
          } else {
            linkStyle = {backgroundColor: 'blue'}
          }
          return(
            <div>
              <a style={this.state.hover ? {"backgroundColor": 'red'}: {"backgroundColor": 'blue'}} onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>Link</a>
            </div>
          )
        }
      

      【讨论】:

        【解决方案12】:

        这对于在 React 组件中具有内联样式(并且还使用 :hover CSS 函数)来说是一个不错的 hack:

        ...
        
        <style>
          {`.galleryThumbnail.selected:hover{outline:2px solid #00c6af}`}
        </style>
        
        ...
        
        

        【讨论】:

          【解决方案13】:

          您可以使用css modules 作为替代方案,另外还可以使用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 modules example

          【讨论】:

          • 仅供参考:如果您使用 Meteor,请查看此软件包:github.com/nathantreid/meteor-css-modules。到目前为止,我自己使用它取得了巨大的成功。
          • 这是设置 react 组件样式的好方法,但不能完全控制内联样式。例如,您不能像使用 Radium 或其他基于 onMouseOver 的解决方案那样在运行时更改 :hover 样式
          【解决方案14】:

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

          例如,渲染一个主题 css 服务器端也是一个很好的解决方案,并且可以保持反应组件更干净。

          如果您不必将动态样式附加到元素(例如用于主题化),则根本不应该使用内联样式,而应使用 css 类。

          这是一个传统的 html/css 规则,用于保持 html/JSX 简洁明了。

          【讨论】:

            【解决方案15】:

            这是使用 CSS 变量的另一个选项。这需要提前定义 css 悬停,所以我猜它不是纯内联的,而是非常少的代码和灵活的。

            css(设置悬停状态):

            .p:hover:{
             color:var(--hover-color) !important,
             opacity:var(--hover-opacity)
            }
            

            反应:

            <p style={{'color':'red','--hover-color':'blue','--hover-opacity':0.5}}>
            

            【讨论】:

            • 这是最好的答案!干净,没有依赖,可以理解,最重要的是,工作!谢谢@yeahdixon
            【解决方案16】:

            这是一个用打字稿编写的通用悬停包装器。该组件将在悬停事件上应用通过 props 'hoverStyle' 传递的样式。

            import React, { useState } from 'react';
            
            export const Hover: React.FC<{
              style?: React.CSSProperties;
              hoverStyle: React.CSSProperties;
            }> = ({ style = {}, hoverStyle, children }) => {
              const [isHovered, setHovered] = useState(false);
              const calculatedStyle = { ...style, ...(isHovered ? hoverStyle : {}) };
              return (
                <div
                  style={calculatedStyle}
                  onMouseEnter={() => setHovered(true)}
                  onMouseLeave={() => setHovered(false)}
                >
                  {children}
                </div>
              );
            };    
            

            【讨论】:

              【解决方案17】:

              这可以通过material-ui makeStyles 调用轻松实现:

              import { makeStyles } from '@material-ui/core/styles';
              
              makeStyles({
                root: {
                  /* … */
                  '&:hover': { /* … */ }
                },
              });
              

              【讨论】:

                【解决方案18】:

                我做了类似于this 的操作,但我不使用material-ui 或makeStyles。我在样式对象的 CSS 中添加了悬停作为条件:

                const styles = {
                  hoverStyle: {
                    color: 'grey',
                    '&:hover': { color: 'blue !important' },
                  }
                };
                
                var NavBar = (props) => {
                  const menuOptions = ['home', 'blog', 'projects', 'about'];
                
                  return (
                    <div>
                      <div>
                        {menuOptions.map((page) => <div style={styles.hoverStyle} key={page}>{page}</div> )}
                      </div>
                    </div>
                  );
                };
                

                这对我有用。

                【讨论】:

                • 它输出:&amp;: hover: [object Object];
                • 只有在项目中集成了 sass 时才可能有效,否则无效(我刚刚测试过,悬停声明被简单地丢弃了)
                【解决方案19】:

                使用钩子:

                const useFade = () => {
                  const [ fade, setFade ] = useState(false);
                
                  const onMouseEnter = () => {
                    setFade(true);
                  };
                
                  const onMouseLeave = () => {
                    setFade(false);
                  };
                
                  const fadeStyle = !fade ? {
                    opacity: 1, transition: 'all .2s ease-in-out',
                  } : {
                    opacity: .5, transition: 'all .2s ease-in-out',
                  };
                
                  return { fadeStyle, onMouseEnter, onMouseLeave };
                };
                
                const ListItem = ({ style }) => {
                  const { fadeStyle, ...fadeProps } = useFade();
                
                  return (
                    <Paper
                      style={{...fadeStyle, ...style}}
                      {...fadeProps}
                    >
                      {...}
                    </Paper>
                  );
                };
                

                【讨论】:

                  【解决方案20】:
                  <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 : {})
                    });
                  }
                  

                  【讨论】:

                    【解决方案21】:

                    我使用这个技巧,内联样式和 css 的混合:

                    //inline-style:
                    const button = {
                      fontSize: "2em",
                    };
                    return (
                      <div style={button} data-hover="button">
                        <style>{`[data-hover="button"]:hover {
                            font-size: 2.1em !important;
                        }`}</style>
                        {this.props.text}
                      </div>
                    );
                    

                    【讨论】:

                      【解决方案22】:

                      我找到了一种简洁的方法,用 useState 周围的包装器,我称之为 useHover
                      不需要额外的库/框架。

                      const App = () => {
                      
                          const hover = useHover({backgroundColor: "LightBlue"})
                      
                          return <p {...hover}>Hover me!</p>
                      }
                      

                      包装代码:

                      function useHover(styleOnHover: CSSProperties, styleOnNotHover: CSSProperties = {})
                      {
                          const [style, setStyle] = React.useState(styleOnNotHover);
                      
                          const onMouseEnter = () => setStyle(styleOnHover)
                          const onMouseLeave = () => setStyle(styleOnNotHover)
                      
                          return {style, onMouseEnter, onMouseLeave}
                      }
                      

                      请注意,useHover 有一个可选的第二个参数,用于当组件未悬停时的样式。

                      试试看here

                      【讨论】:

                        【解决方案23】:

                        我在我最近的一个应用程序中使用了一个非常 hack-ish 的解决方案,它适用于我的目的,我发现它比在 vanilla js 中编写自定义悬停设置函数更快(虽然,我承认,也许不是最佳实践在大多数环境中..) 所以,如果你仍然感兴趣,那就去吧。

                        我创建一个父元素只是为了保存内联 javascript 样式,然后创建一个具有 className 或 id 的子元素,我的 css 样式表将锁定并在我的专用 css 文件中写入悬停样式。这是因为更细粒度的子元素通过继承接收内联 js 样式,但其悬停样式被 css 文件覆盖。

                        所以基本上,我的实际 css 文件存在的唯一目的是保持悬停效果,仅此而已。这使它非常简洁且易于管理,并允许我在我的内联 React 组件样式中完成繁重的工作。

                        这是一个例子:

                        const styles = {
                          container: {
                            height: '3em',
                            backgroundColor: 'white',
                            display: 'flex',
                            flexDirection: 'row',
                            alignItems: 'stretch',
                            justifyContent: 'flex-start',
                            borderBottom: '1px solid gainsboro',
                          },
                          parent: {
                            display: 'flex',
                            flex: 1,
                            flexDirection: 'row',
                            alignItems: 'stretch',
                            justifyContent: 'flex-start',
                            color: 'darkgrey',
                          },
                          child: {
                            width: '6em',
                            textAlign: 'center',
                            verticalAlign: 'middle',
                            lineHeight: '3em',
                          },
                        };
                        
                        var NavBar = (props) => {
                          const menuOptions = ['home', 'blog', 'projects', 'about'];
                        
                          return (
                            <div style={styles.container}>
                              <div style={styles.parent}>
                                {menuOptions.map((page) => <div className={'navBarOption'} style={styles.child} key={page}>{page}</div> )}
                              </div>
                            </div>
                          );
                        };
                        
                        
                        ReactDOM.render(
                          <NavBar/>,
                          document.getElementById('app')
                        );
                        .navBarOption:hover {
                          color: black;
                        }
                        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
                        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
                        
                        <div id="app"></div>

                        请注意,“child”内联样式没有设置“color”属性。如果是这样,这将不起作用,因为内联样式将优先于我的样式表。

                        【讨论】:

                          【解决方案24】:

                          我不能 100% 确定这是否是答案,但它是我用来模拟 CSS 的技巧:内嵌颜色和图像的悬停效果。

                          `This works best with an image`
                          
                          class TestHover extends React.PureComponent {
                          render() {
                          const landingImage = {     
                          "backgroundImage": "url(https://i.dailymail.co.uk/i/pix/2015/09/01/18/2BE1E88B00000578-3218613-image-m-5_1441127035222.jpg)",
                          "BackgroundColor": "Red", `this can be any color`
                          "minHeight": "100%",
                          "backgroundAttachment": "fixed",
                          "backgroundPosition": "center",
                          "backgroundRepeat": "no-repeat",
                          "backgroundSize": "cover", 
                          "opacity": "0.8", `the hove trick is here in the opcaity slightly see through gives the effect when the background color changes`
                              }
                          
                            return (
                              <aside className="menu">
                                  <div className="menu-item">
                                    <div style={landingImage}>SOME TEXT</div>
                                  </div>
                              </aside>
                                ); 
                            }
                          }
                          ReactDOM.render(
                              <TestHover />,
                            document.getElementById("root")
                          );
                          

                          CSS:

                          .menu {
                          top: 2.70em;
                          bottom: 0px;
                          width: 100%;
                          position: absolute;
                          }
                          
                          .menu-item {
                          cursor: pointer;
                          height: 100%;
                          font-size: 2em;
                          line-height: 1.3em;
                          color: #000;
                          font-family: "Poppins";
                          font-style: italic;
                          font-weight: 800;
                          text-align: center;
                          display: flex;
                          flex-direction: column;
                          justify-content: center;
                          }
                          

                          悬停前

                          .menu-item:nth-child(1) {
                          color: white;
                          background-color: #001b37;
                          } 
                          

                          悬停时

                          .menu-item:nth-child(1):hover {
                          color: green;
                          background-color: white;
                          }
                          

                          示例:https://codepen.io/roryfn/pen/dxyYqj?editors=0011

                          【讨论】:

                            【解决方案25】:

                            您可以创建一个 abstract 悬停类,例如颜色。

                            .hoverClassColor:hover {
                              color:var(--hover-color) !important;
                            }
                            

                            然后对于所有想要在悬停时将颜色更改为red 的元素:

                            render() {
                              return <a className={'hoverClassColor'} style={{'--hover-color':'red'}}>Test</a>
                            }
                            

                            对我来说,它就像内联,因为这些类是抽象的,可以重复用于您想要实现颜色悬停的所有元素。

                            【讨论】:

                              猜你喜欢
                              • 2015-04-08
                              • 2010-11-05
                              • 2021-06-10
                              • 2020-11-18
                              • 2020-02-15
                              • 2017-06-15
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多