Inline CSS styles in React: come implementare un: hover?


178

Mi piace abbastanza il modello CSS incorporato in React e ho deciso di usarlo.

Tuttavia, non è possibile utilizzare i :hoverselettori e simili. Qual è il modo migliore per implementare l'evidenziazione al passaggio del mouse durante l'utilizzo di stili CSS in linea?

Un suggerimento di #reactjs è di avere un Clickablecomponente e usarlo in questo modo:

<Clickable>
    <Link />
</Clickable>

L' Clickableha una hoveredcondizione e lo passa come oggetti di scena al link. Tuttavia, il Clickable(il modo in cui l'ho implementato) avvolge Linkin a in divmodo che possa essere impostato onMouseEntere onMouseLeavead esso. Questo rende le cose un po 'complicate (ad es. spanAvvolte in un divcomportamento diverso da span).

c'è un modo più facile?


1
Hai assolutamente ragione - l'unico modo per simulare: passa il mouse con i selettori ecc. Con stili incorporati è usare onMouseEntere onMouseLeave. Per quanto riguarda la sua esatta attuazione, dipende interamente da te. Per guardare il tuo esempio specifico, perché non rendere il <Clickable/>wrapper un span?
Chris Houghton,

3
ti suggerirei di utilizzare fogli di stile esterni insieme al plug-in Estratto Webpack, questo ti aiuterà a correre più a lungo se mai desideri ServerRender altrimenti puoi provare Radium github.com/FormidableLabs/radium
abhirathore2006

Attualmente Styled Component è la soluzione migliore per simulare tutte le possibilità di css / scss in reagire.
Ahmad Behzadi,

Risposte:


43

Sono nella stessa situazione. Mi piace molto il modello di mantenere lo stile nei componenti, ma gli stati al passaggio del mouse sembrano l'ultimo ostacolo.

Quello che ho fatto è stato scrivere un mixin che puoi aggiungere al tuo componente che necessita degli stati al passaggio del mouse. Questo mixin aggiungerà una nuova hoveredproprietà allo stato del componente. Verrà impostato su truese l'utente passa sopra il nodo DOM principale del componente e lo reimposta su falsese l'utente lascia l'elemento.

Ora nella funzione di rendering del componente puoi fare qualcosa del tipo:

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

Ora, ogni volta che lo hoveredstato cambia, il componente viene reso nuovamente.

Ho anche creato un repository sandbox per questo che uso per testare personalmente alcuni di questi schemi. Dai un'occhiata se vuoi vedere un esempio della mia implementazione.

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


3
non è una buona soluzione per un periodo più lungo, Radium sarà una scelta migliore o utilizzerà un foglio di stile esterno
abhirathore2006

16
@ abhirathore2006 Radium funziona allo stesso modo e la domanda è in particolare come farlo senza utilizzare un foglio di stile esterno
Charlie Martin

Non avrebbe più senso usare un operatore di diffusione alla vaniglia?
PAT-O-MATION

102

Penso che onMouseEnter e onMouseLeave siano le strade da percorrere, ma non vedo la necessità di un componente wrapper aggiuntivo. Ecco come l'ho implementato:

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

È quindi possibile utilizzare lo stato del passaggio del mouse (vero / falso) per modificare lo stile del collegamento.


1
Questo sembra coprire :hoverma non:focus
Adam Tuttle

3
@AdamTuttle reazioni ha un onFocusevento; così si potrebbe fare la stessa cosa per :focusquanto :hover, tranne che invece di aver bisogno onMouseEntere onMouseLeavesi avrebbe solo bisognoonFocus
Jonathan

7
Tieni presente che questo metodo forza l'esecuzione sul thread principale mentre gli eventi CSS tipici vengono gestiti in modo molto più efficiente.
Hampus Ahlgren,

54

In ritardo per festeggiare, ma vieni con una soluzione. Puoi usare "&" per definire gli stili al passaggio del mouse su Child 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
Questa non è una soluzione, la domanda era come farlo con INLINE css, non con un foglio di stile separato.
Emmy,

36
Amico, dai un'occhiata più da vicino. Questo è uno stile in linea.
Jarosław Wlazło,

15
Questo non funziona con React. Hai bisogno di una libreria extra come componenti con stile.
GG.

3
Non funziona con uno stile in linea, questo esempio crea confusione. Se funziona davvero, fornisci un esempio migliore con il componente completo.
Alexandre,

2
Eccellente! Funziona come un fascino!
Fyodor l'

26

Puoi usare Radium: è uno strumento open source per stili in linea con ReactJS. Aggiunge esattamente i selettori di cui hai bisogno. Molto popolare, dai un'occhiata - Radium su npm


Mi sono appena imbattuto in questo post, come implementeresti Radium nella seguente situazione? module.exports = React.createClass({ displayName: 'App',})

1
@Rkhayat Puoi racchiuderlo module.exports = Radium(React.createClass({ displayName: 'App',}))o assegnare la classe a un valore e aggiungere il @Radiumdecoratore sopra di esso come menziona la documentazione github.com/FormidableLabs/radium#usage
pbojinov

c'è anche questa grande cosa chiamata CSS;)
Pixelomo

11

Il pieno supporto CSS è esattamente il motivo per cui questa enorme quantità di librerie CSSinJS, per farlo in modo efficiente, è necessario generare CSS reali, non stili incorporati. Anche gli stili in linea sono molto più lenti a reagire in un sistema più grande. Dichiarazione di non responsabilità - mantengo JSS .


9

Made Style It - in parte - per questo motivo (altri essendo in disaccordo con l'implementazione di altre libs / sintassi e stili inline mancano di supporto per il prefisso dei valori delle proprietà). Crediamo che dovremmo essere in grado di scrivere semplicemente CSS in JavaScript e avere componenti completamente autonomi HTML-CSS-JS. Con le stringhe modello ES5 / ES6 ora possiamo e può essere anche abbastanza! :)

npm install style-it --save

Sintassi funzionale ( 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;

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

Ho notato nell'esempio di sintassi JSX, il collegamento JSFiddle ha il codice corretto, ma nell'esempio mostrato qui manca la parentesi di chiusura dopo il tag Style di chiusura e il rientro è disattivato probabilmente a causa della parentesi mancante.
Bradley Smith,

8

Aggiungendo alla risposta di Jonathan , ecco gli eventi per coprire il focus e gli stati attivi, e un utilizzo onMouseOveranziché onMouseEnterpoiché quest'ultimo non farà bolle se ci sono elementi figlio all'interno del target a cui viene applicato l'evento.

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

Ecco la mia soluzione usando React Hooks. Combina l'operatore di diffusione e l'operatore ternario.

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

Per quanto riguarda i componenti di stile e il reagente-router v4 , puoi fare questo:

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

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

  &:hover {
    color: white;
  }
`

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

6

Questo può essere un bel trucco per avere uno stile inline all'interno di un componente reagire (e anche usando: hover funzione CSS):

...

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

...

5

Checkout Typestyle se si utilizza reagire con tipografico.

Di seguito è riportato un codice di esempio per: 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

È possibile utilizzare i moduli CSS in alternativa e inoltre reagire con i moduli CSS per la mappatura dei nomi di classe.

In questo modo puoi importare i tuoi stili come segue e usare i normali css con ambito localmente nei tuoi componenti:

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

Ecco un esempio di moduli css webpack


Cordiali saluti: Se stai usando Meteor controlla questo pacchetto: github.com/nathantreid/meteor-css-modules . Lo sto usando da solo e ho avuto un grande successo finora.
Spiralis,

Questo è un ottimo modo per modellare i componenti di reazione, ma non ti dà tutto il controllo degli stili in linea. Ad esempio, non è possibile modificare gli :hoverstili in fase di esecuzione come è possibile con Radium o un'altra onMouseOversoluzione basata
Charlie Martin,

4

onMouseOver e onMouseLeave all'inizio con setState mi sono sembrati un po 'sovraccarichi, ma poiché è così che funziona la reazione, mi sembra la soluzione più semplice e pulita.

il rendering di un lato server CSS tematico, ad esempio, è anche una buona soluzione e mantiene i componenti di reazione più puliti.

se non devi aggiungere stili dinamici agli elementi (ad esempio per un tema) non dovresti usare affatto gli stili inline ma usa invece le classi css.

questa è una regola html / css tradizionale per mantenere html / JSX pulito e semplice.


4

Il modo semplice è usare l'operatore ternario

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

Con l'utilizzo dei ganci:

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

Uso una soluzione piuttosto hacker per questo in una delle mie recenti applicazioni che funziona per i miei scopi, e lo trovo più veloce rispetto alla scrittura di funzioni personalizzate di impostazione al passaggio del mouse in vanilla js (anche se, lo riconosco, forse non è una buona pratica nella maggior parte degli ambienti ..) Quindi, nel caso tu sia ancora interessato, ecco qui.

Creo un elemento genitore solo per il gusto di contenere gli stili javascript in linea, quindi un bambino con un className o un ID su cui il mio foglio di stile CSS si aggancerà e scriverà lo stile al passaggio del mouse nel mio file CSS dedicato. Questo funziona perché l'elemento figlio più granulare riceve gli stili js inline tramite ereditarietà, ma i suoi stili hover sovrascritti dal file css.

Quindi, fondamentalmente, il mio vero file css esiste al solo scopo di contenere effetti hover, nient'altro. Questo lo rende piuttosto conciso e facile da gestire, e mi permette di fare il duro lavoro nei miei stili di componenti React in linea.

Ecco un esempio:

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>

Si noti che lo stile inline "figlio" non ha un set di proprietà "color". In caso contrario, ciò non funzionerebbe perché lo stile in linea avrebbe la precedenza sul mio foglio di stile.


0

Non sono sicuro al 100% se questa è la risposta, ma è il trucco che uso per simulare il CSS: effetto hover con colori e immagini in linea.

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

Prima di passare il mouse

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

Al passaggio del mouse

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

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


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

Dove Hoverable è definito come:

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 : {})
  });
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.