React中的内联CSS样式:如何实现a:hover?


177

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

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

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

<Clickable>
    <Link />
</Clickable>

Clickable有一个hovered状态,并将其作为道具的链接。但是,Clickable(我的方式来实现它)包裹Linkdiv,以便它可以设置onMouseEnteronMouseLeave给它。不过,这会使事情有些复杂(例如,span包裹在div行为上与有所不同span)。

有没有更简单的方法?


1
您绝对正确-使用内联样式模拟:hover等选择器的唯一方法是使用onMouseEnterand onMouseLeave。关于确切的实现-这完全取决于您。为了查看您的特定示例,为什么不将<Clickable/>包装器设置为a span
克里斯·霍顿

3
我建议将外部样式表与ExtractText Webpack插件一起使用,如果您希望使用ServerRender,则可以帮助您长期运行,否则可以尝试Radium github.com/FormidableLabs/radium
abhirathore2006

当前样式化的组件是模拟css / scss反应的所有可能性的最佳解决方案。
艾哈迈德·贝扎迪

Answers:


43

我处于同样的情况。确实像在组件中保留样式的模式,但是悬停状态似乎是最后的障碍。

我所做的是编写一个mixin,您可以将其添加到需要悬停状态的组件中。这个混入将向hovered您的组件状态添加一个新属性。它将被设置为true,如果在组件,并设置主DOM节点的用户悬停回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


3
如果不是长期运行的好解决方案,则Radium将是更好的选择,或者使用外部样式表
abhirathore2006 16/08/17

16
@ abhirathore2006 Radium的工作方式相同,问题特别是如何在不使用外部样式表的情况下做到这一点
Charlie Martin

使用香草扩散算子会更有意义吗?
PAT-O-MATION

102

我认为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>
    )
}

然后,您可以使用悬停状态(true / false)更改链接的样式。


1
这似乎可以解决:hover但不能覆盖:focus
Adam Tuttle

3
@AdamTuttle react有一个onFocus事件;所以你可以对做同样的事情:focus:hover,除了没有需要onMouseEnteronMouseLeave你只需要onFocus
乔纳森

7
请注意,此方法会强制在主线程上执行,而典型CSS事件的处理效率更高。
汉普斯·阿赫格伦

53

晚会,但要有解决方案。您可以使用“&”来定义第n个Child等的样式:

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"
    }
},

1
这不是解决方案,问题是如何使用INLINE CSS(而不是单独的样式表)来实现。
艾美奖

34
杜德,仔细看看。这是内联样式。
雅罗斯瓦夫Wlazło

14
这不适用于React。您需要一个额外的库,例如样式组件。
GG。

3
它不适用于嵌入式样式,此示例带来了混乱。如果确实可行,请提供一个完整示例的更好示例。
亚历山大

2
优秀的!奇迹般有效!
Fyodor

26

您可以使用Radium-它是ReactJS用于内联样式的开源工具。它恰好添加了您需要的选择器。非常受欢迎,请查看-Radium on npm


我刚刚看到这篇文章,在以下情况下您将如何实施Radium?module.exports = React.createClass({ displayName: 'App',})

1
@Rkhayat您可以将其包装为module.exports = Radium(React.createClass({ displayName: 'App',}))或为该类分配一个值,并在其@Radium上方添加装饰器,如文档所述github.com/FormidableLabs/radium#usage
pbojinov 2016年

还有一个很棒的东西叫做CSS;)
Pixelomo '18

11

完全的CSS支持正是这大量CSSinJS库有效运行的原因,您需要生成实际的CSS,而不是内联样式。此外,在较大的系统中,内联样式的响应速度要慢得多。免责声明-我维护JSS


9

Made Style It(部分原因)是由于这个原因(其他人则不同意其他lib /语法的实现和内联样式缺乏对前缀属性值的支持)。相信我们应该能够简单地用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链接具有正确的代码,但是此处显示的示例在关闭Style标记后缺少了右括号,并且缩进被关闭,可能是因为缺少了括号。
bradleygsmith

8

除了乔纳森(Jonathan)的答案,以下是涵盖焦点和活动状态的事件,以及使用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>
    )
  }

7

这是我使用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>
  )
}


6

对于在react组件中具有内联样式(以及还使用:hover CSS函数),这可能是一个不错的技巧:

...

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

...

5

结帐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>

4

您可以使用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模块示例


仅供参考:如果您使用的是Meteor,请查看以下软件包:github.com/nathantreid/meteor-css-modules。到目前为止,我自己一直在成功使用它。
Spiralis

这是一种对组件进行样式设置的好方法,但并不能完全控制内联样式。例如,您无法:hover像在Radium或其他onMouseOver基于解决方案的运行时那样更改运行时的样式
Charlie Martin

4

刚开始使用setState的onMouseOver和onMouseLeave对我来说似乎有些负担-但这是React的工作方式,这对我来说似乎是最简单,最干净的解决方案。

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

如果您不必在元素上添加动态样式(例如用于theming),则根本不应该使用内联样式,而应使用css类。

这是保持html / JSX干净和简单的传统html / css规则。


4

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

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>
    )
  }

0

我在我的一个针对我的目的的最新应用程序中为此使用了一个漂亮的解决方案,并且发现它比在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>

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


0

使用钩子:

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>
  );
};

0

我不是100%确定这是否是答案,但是我使用内联颜色和图像来模拟CSS:hover效果的技巧。

`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


0
<Hoverable hoverStyle={styles.linkHover}>
  <a href="https://example.com" style={styles.link}>
    Go
  </a>
</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 : {})
  });
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.