Styles CSS en ligne dans React: comment implémenter un: hover?


178

J'aime assez le modèle CSS en ligne dans React et j'ai décidé de l'utiliser.

Cependant, vous ne pouvez pas utiliser les :hoversélecteurs et similaires. Alors, quelle est la meilleure façon d'implémenter la mise en évidence au survol tout en utilisant des styles CSS en ligne?

Une suggestion de #reactjs est d'avoir un Clickablecomposant et de l'utiliser comme ceci:

<Clickable>
    <Link />
</Clickable>

Le Clickablea un hoveredétat et le transmet comme accessoires au lien. Cependant, Clickable(la façon dont je l'ai implémenté) enveloppe le Linkdans un divafin qu'il puisse définir onMouseEnteret onMouseLeavey accéder. Cela rend les choses un peu compliquées (par exemple, spanenveloppé dans un divse comporte différemment span).

Existe-t-il un moyen plus simple?


1
Vous avez tout à fait raison - le seul moyen de simuler: les sélecteurs de survol, etc. avec des styles en ligne est d'utiliser onMouseEnteret onMouseLeave. En ce qui concerne la mise en œuvre exacte de cela, cela dépend entièrement de vous. Pour regarder votre exemple spécifique, pourquoi ne pas faire de l' <Clickable/>emballage un span?
Chris Houghton

3
Je suggérerais d'utiliser des feuilles de style externes avec le plugin ExtractText Webpack, cela vous aidera à plus long terme si vous souhaitez un jour ServerRender sinon vous pouvez essayer Radium github.com/FormidableLabs/radium
abhirathore2006

Actuellement Styled Component est la meilleure solution pour simuler toutes les possibilités de css / scss dans react.
Ahmad Behzadi

Réponses:


43

Je suis dans la même situation. Vraiment comme le modèle de maintien du style dans les composants, mais les états de survol semblent être le dernier obstacle.

Ce que j'ai fait, c'est d'écrire un mixin que vous pouvez ajouter à votre composant qui nécessite des états de survol. Ce mixin ajoutera une nouvelle hoveredpropriété à l'état de votre composant. Il sera défini sur truesi l'utilisateur survole le nœud DOM principal du composant et le réinitialise falsesi les utilisateurs quittent l'élément.

Maintenant, dans votre fonction de rendu de composant, vous pouvez faire quelque chose comme:

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

Désormais, chaque fois que l'état de l' hoveredétat change, le composant sera renvoyé.

J'ai également créé un dépôt sandbox pour cela que j'utilise pour tester moi-même certains de ces modèles. Vérifiez-le si vous voulez voir un exemple de ma mise en œuvre.

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


3
pas une bonne solution pour une plus longue durée, Radium sera un meilleur choix ou en utilisant une feuille de style externe
abhirathore2006

16
@ abhirathore2006 Radium fonctionne de la même manière et la question est spécifiquement de savoir comment faire cela sans utiliser de feuille de style externe
Charlie Martin

N'aurait-il pas plus de sens d'utiliser un opérateur de tartinade à la vanille?
PAT-O-MATION

102

Je pense que onMouseEnter et onMouseLeave sont les voies à suivre, mais je ne vois pas la nécessité d'un composant wrapper supplémentaire. Voici comment je l'ai implémenté:

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

Vous pouvez ensuite utiliser l'état de survol (vrai / faux) pour changer le style du lien.


1
Cela semblerait couvrir :hovermais pas:focus
Adam Tuttle

3
@AdamTuttle react a un onFocusévénement; donc vous pourriez faire la même chose pour :focuscomme :hover, sauf au lieu d'avoir besoin onMouseEnteret onMouseLeavevous n'en auriez besoin queonFocus
Jonathan

7
Sachez que cette méthode force l'exécution sur le thread principal alors que les événements CSS typiques sont gérés beaucoup plus efficacement.
Hampus Ahlgren

54

En retard pour faire la fête mais avec une solution. Vous pouvez utiliser "&" pour définir les styles de survol du nième enfant, etc.:

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
Ce n'est pas une solution, la question était de savoir comment le faire avec INLINE css, pas avec une feuille de style séparée.
Emmy

36
Mec, regarde de plus près. Ce style est en ligne.
Jarosław Wlazło

15
Cela ne fonctionne pas avec React. Vous avez besoin d'une bibliothèque supplémentaire comme les composants stylisés.
GG.

3
Cela ne fonctionne pas avec le style en ligne, cet exemple est source de confusion. Si cela fonctionne vraiment, veuillez fournir un meilleur exemple avec un composant complet.
Alexandre

2
Excellent! Fonctionne comme un charme!
Fyodor

26

Vous pouvez utiliser Radium - c'est un outil open source pour les styles en ligne avec ReactJS. Il ajoute exactement les sélecteurs dont vous avez besoin. Très populaire, vérifiez-le - Radium sur npm


Je viens de tomber sur ce post, comment implémenteriez-vous Radium dans la situation suivante? module.exports = React.createClass({ displayName: 'App',})

1
@Rkhayat Vous pouvez soit l'envelopper en tant que module.exports = Radium(React.createClass({ displayName: 'App',}))ou attribuer la classe à une valeur et ajouter le @Radiumdécorateur au-dessus comme la documentation mentionne github.com/FormidableLabs/radium#usage
pbojinov

il y a aussi cette grande chose appelée CSS;)
Pixelomo

11

Le support CSS complet est exactement la raison pour laquelle cette énorme quantité de bibliothèques CSSinJS, pour le faire efficacement, vous devez générer du CSS réel, pas des styles en ligne. Les styles en ligne sont également beaucoup plus lents à réagir dans un système plus grand. Clause de non-responsabilité - Je maintiens JSS .


9

Made Style It - en partie - à cause de cette raison (d'autres étant des désaccords avec l'implémentation d'autres libs / syntaxes et les styles en ligne manquent de support pour le préfixage des valeurs de propriété). Croyez que nous devrions être capables d'écrire simplement du CSS en JavaScript et d'avoir des composants entièrement autonomes HTML-CSS-JS. Avec les chaînes de modèles ES5 / ES6, nous pouvons maintenant et cela peut être joli aussi! :)

npm install style-it --save

Syntaxe fonctionnelle ( 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;

Syntaxe 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;

J'ai remarqué dans l'exemple de syntaxe JSX, le lien JSFiddle a le code correct, mais l'exemple montré ici manque la parenthèse fermante après la balise Style de fermeture et l'indentation est probablement désactivée à cause de la parenthèse manquante.
bradleygsmith

8

En plus de la réponse de Jonathan , voici les événements pour couvrir le focus et les états actifs, et une utilisation onMouseOverau lieu de onMouseEnterpuisque ce dernier ne bouillonnera pas si vous avez des éléments enfants dans la cible à laquelle l'événement est appliqué.

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

Voici ma solution en utilisant React Hooks. Il combine l'opérateur d'étalement et l'opérateur ternaire.

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

En ce qui concerne les composants stylisés et react-router v4, vous pouvez le faire:

import {NavLink} from 'react-router-dom'

const Link = styled(NavLink)`     
  background: blue;

  &:hover {
    color: white;
  }
`

...
<Clickable><Link to="/somewhere">somewhere</Link></Clickable>

6

Cela peut être un bon hack pour avoir un style en ligne dans un composant de réaction (et également en utilisant la fonction CSS hover):

...

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

...

5

Commander Styles de police si vous utilisez React avec Typescript.

Voici un exemple de code pour: 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

Vous pouvez utiliser des modules css comme alternative, et en plus react-css-modules pour le mappage des noms de classe.

De cette façon, vous pouvez importer vos styles comme suit et utiliser le CSS normal étendu localement à vos composants:

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

Voici un exemple de modules css webpack


FYI: Si vous utilisez Meteor, consultez ce package: github.com/nathantreid/meteor-css-modules . Je l'utilise moi-même avec un grand succès jusqu'à présent.
Spiralis

C'est un excellent moyen de styliser les composants de réaction, mais ne vous donne pas tout le contrôle des styles en ligne. Par exemple, vous ne pouvez pas modifier les :hoverstyles au moment de l'exécution comme vous pouvez le faire avec Radium ou une autre onMouseOversolution basée
Charlie Martin

4

onMouseOver et onMouseLeave avec setState m'ont d'abord semblé un peu trop compliqué - mais comme c'est ainsi que fonctionne React, cela me semble la solution la plus simple et la plus propre.

le rendu d'un côté serveur css de thème par exemple, est également une bonne solution et maintient les composants de réaction plus propres.

si vous n'avez pas à ajouter de styles dynamiques aux éléments (par exemple pour une thématisation), vous ne devez pas du tout utiliser de styles en ligne mais utilisez plutôt des classes css.

c'est une règle traditionnelle html / css pour garder html / JSX propre et simple.


4

Le moyen simple consiste à utiliser l'opérateur ternaire

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

1

Avec une utilisation des crochets:

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

J'utilise une solution assez hack-ish pour cela dans l'une de mes applications récentes qui fonctionne pour mes besoins, et je trouve cela plus rapide que d'écrire des fonctions de paramètres de survol personnalisés dans vanilla js (bien que, je reconnais, peut-être pas une meilleure pratique dans la plupart des environnements ..) Donc, au cas où vous seriez toujours intéressé, allez-y.

Je crée un élément parent juste pour le plaisir de contenir les styles javascript en ligne, puis un enfant avec un nom de classe ou un identifiant sur lequel ma feuille de style css s'accrochera et écrira le style de survol dans mon fichier css dédié. Cela fonctionne car l'élément enfant le plus granulaire reçoit les styles js en ligne via l'héritage, mais ses styles de survol sont remplacés par le fichier css.

Donc, fondamentalement, mon fichier css existe dans le seul but de contenir des effets de survol, rien d'autre. Cela le rend assez concis et facile à gérer, et me permet de faire le gros du travail dans mes styles de composants React en ligne.

Voici un exemple:

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>

Notez que le style en ligne "enfant" n'a pas de jeu de propriétés "couleur". Si c'était le cas, cela ne fonctionnerait pas car le style en ligne prévaudrait sur ma feuille de style.


0

Je ne suis pas sûr à 100% si c'est la réponse, mais c'est l'astuce que j'utilise pour simuler le CSS: effet de survol avec des couleurs et des images en ligne.

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

Avant de survoler

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

En vol stationnaire

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

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


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

Où Hoverable est défini comme:

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 : {})
  });
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.