Inline-CSS-Stile in React: Wie implementiere ich einen: Hover?

178

Ich mag das Inline-CSS-Muster in React sehr und habe beschlossen, es zu verwenden.

Sie können jedoch keine :hoverund ähnliche Selektoren verwenden. Was ist der beste Weg, um Highlight-on-Hover bei Verwendung von Inline-CSS-Stilen zu implementieren?

Ein Vorschlag von #reactjs ist, eine ClickableKomponente zu haben und sie wie folgt zu verwenden:

<Clickable>
    <Link />
</Clickable>

Der Clickablehat einen hoveredZustand und gibt ihn als Requisiten an den Link weiter. Allerdings ist die Clickable(wie ich es implementiert) wickelt die Linkin einem divso dass es einstellen onMouseEnterund onMouseLeavedarauf. Dies macht die Dinge allerdings etwas kompliziert (z. B. spanverpackt in ein divVerhalten anders als span).

Gibt es einen einfacheren Weg?

fhucho
quelle
1
Sie haben absolut Recht - die einzige Möglichkeit zu simulieren: Hover usw. Selektoren mit Inline-Stilen ist die Verwendung von onMouseEnterund onMouseLeave. In Bezug auf die genaue Umsetzung liegt es ganz bei Ihnen. Um Ihr spezielles Beispiel zu betrachten, warum machen Sie den <Clickable/>Wrapper nicht zu einem span?
Chris Houghton
3
Ich würde vorschlagen, externe Stylesheets zusammen mit dem ExtractText Webpack-Plugin zu verwenden. Dies hilft Ihnen bei längerer Ausführung, wenn Sie jemals ServerRender verwenden möchten. Andernfalls können Sie Radium github.com/FormidableLabs/radium
abhirathore2006 vom
Derzeit ist Styled Component die beste Lösung, um alle Möglichkeiten von CSS / SCS in Reaktion zu simulieren.
Ahmad Behzadi

Antworten:

43

Ich bin in der gleichen Situation. Mag das Muster, das Styling in den Komponenten beizubehalten, aber die Schwebezustände scheinen die letzte Hürde zu sein.

Ich habe ein Mixin geschrieben, das Sie zu Ihrer Komponente hinzufügen können, die Schwebezustände benötigt. Dieses Mixin fügt hovereddem Status Ihrer Komponente eine neue Eigenschaft hinzu. Es wird festgelegt, trueob der Benutzer den Mauszeiger über den Haupt-DOM-Knoten der Komponente bewegt, und zurückgesetzt, falsewenn der Benutzer das Element verlässt.

Jetzt können Sie in Ihrer Komponenten-Renderfunktion Folgendes tun:

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

Jedes Mal, wenn sich der Status des hoveredStatus ändert, wird die Komponente erneut gerendert.

Ich habe auch ein Sandbox-Repo dafür erstellt, mit dem ich einige dieser Muster selbst teste. Probieren Sie es aus, wenn Sie ein Beispiel für meine Implementierung sehen möchten.

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

Wim Mostmans
quelle
3
Radium ist keine gute Lösung für eine längere Laufzeit. Es ist die bessere Wahl oder die Verwendung eines externen Stylesheets
abhirathore2006
16
@ abhirathore2006 Radium funktioniert genauso und die Frage ist speziell, wie man dies ohne Verwendung eines externen Stylesheets macht
Charlie Martin
Wäre es nicht sinnvoller, einen Vanille-Spread-Operator zu verwenden?
PAT-O-MATION
102

Ich denke, onMouseEnter und onMouseLeave sind die richtigen Wege, aber ich sehe keine Notwendigkeit für eine zusätzliche Wrapper-Komponente. So habe ich es implementiert:

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

Sie können dann den Schwebezustand (wahr / falsch) verwenden, um den Stil des Links zu ändern.

Jonathan
quelle
1
Dies scheint zu decken, :hoveraber nicht:focus
Adam Tuttle
3
@AdamTuttle reagieren hat ein onFocusEreignis; so dass Sie die gleiche Sache für tun könnten , :focuswie :hover, es sei denn statt der Notwendigkeit onMouseEnterund onMouseLeaveSie würden nur brauchenonFocus
Jonathan
7
Beachten Sie, dass diese Methode die Ausführung im Hauptthread erzwingt, während typische CSS-Ereignisse viel effizienter behandelt werden.
Hampus Ahlgren
53

Spät zum Feiern, aber mit Lösung. Sie können "&" verwenden, um Stile für das schwebende n-te Kind usw. zu definieren:

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"
    }
},
Hitesh Sahu
quelle
1
Dies ist keine Lösung, die Frage war, wie es mit INLINE-CSS geht, nicht mit einem separaten Stylesheet.
Emmy
34
Alter, schau genauer hin. Dies ist Inline-Stil.
Jarosław Wlazło
15
Dies funktioniert nicht mit React. Sie benötigen eine zusätzliche Bibliothek wie gestylte Komponenten.
GG.
3
Es funktioniert nicht mit Inline-Stil, dieses Beispiel bringt Verwirrung. Wenn es wirklich funktioniert, geben Sie bitte ein besseres Beispiel mit vollständiger Komponente an.
Alexandre
2
Ausgezeichnet! Klappt wunderbar!
Fjodor
26

Sie können Radium verwenden - es ist ein Open Source-Tool für Inline-Stile mit ReactJS. Es werden genau die Selektoren hinzugefügt, die Sie benötigen. Sehr beliebt, probieren Sie es aus - Radium auf npm

Gyro
quelle
Ich bin gerade auf diesen Beitrag gestoßen. Wie würden Sie Radium in der folgenden Situation implementieren? module.exports = React.createClass({ displayName: 'App',})
1
@Rkhayat Sie können es entweder als einschließen module.exports = Radium(React.createClass({ displayName: 'App',}))oder die Klasse einem Wert zuweisen und den @RadiumDekorator darüber hinzufügen , wie in den Dokumenten erwähnt, github.com/FormidableLabs/radium#usage
pbojinov
Es gibt auch diese großartige Sache namens CSS;)
Pixelomo
11

Die vollständige CSS-Unterstützung ist genau der Grund für diese große Anzahl von CSSinJS-Bibliotheken. Um dies effizient zu tun, müssen Sie tatsächlich CSS und keine Inline-Stile generieren. Auch Inline-Stile reagieren in einem größeren System viel langsamer. Haftungsausschluss - Ich pflege JSS .

Oleg Isonen
quelle
9

Made Style It - teilweise - aus diesem Grund (andere sind nicht einverstanden mit der Implementierung anderer Bibliotheken / Syntax- und Inline-Stile, da das Präfixieren von Eigenschaftswerten nicht unterstützt wird). Glauben Sie, wir sollten in der Lage sein, einfach CSS in JavaScript zu schreiben und vollständig in sich geschlossene Komponenten HTML-CSS-JS zu haben. Mit ES5 / ES6-Template-Strings können wir jetzt und es kann auch schön sein! :) :)

npm install style-it --save

Funktionssyntax ( 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-Syntax ( 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;
Joshua Robinson
quelle
Im JSX-Syntaxbeispiel ist mir aufgefallen, dass der JSFiddle-Link den richtigen Code enthält. In dem hier gezeigten Beispiel fehlt jedoch die schließende Klammer nach dem schließenden Style-Tag, und der Einzug ist wahrscheinlich aufgrund der fehlenden Klammer deaktiviert.
Bradleygsmith
8

Zusätzlich zu Jonathans Antwort sind hier die Ereignisse aufgeführt, die den Fokus und die aktiven Zustände abdecken, und eine Verwendung onMouseOveranstelle von, onMouseEnterda letztere nicht sprudelt, wenn Sie untergeordnete Elemente innerhalb des Ziels haben, auf das das Ereignis angewendet wird.

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>
    )
  }
Rachel Cantor
quelle
7

Hier ist meine Lösung mit React Hooks. Es kombiniert den Spread-Operator und den ternären Operator.

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>
  )
}
PAT-O-MATION
quelle
6

In Bezug auf gestylte Komponenten und React-Router v4 können Sie dies tun:

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

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

  &:hover {
    color: white;
  }
`

...
<Clickable><Link to="/somewhere">somewhere</Link></Clickable>
Isaac Pak
quelle
6

Dies kann ein guter Hack sein, um einen Inline-Stil in einer Reaktionskomponente zu haben (und auch die Hover-CSS-Funktion zu verwenden):

...

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

...
tomericco
quelle
5

Kasse Typestyle wenn Sie React with Typescript verwenden.

Unten finden Sie einen Beispielcode für: 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>
Paibambus
quelle
4

Alternativ können Sie CSS-Module verwenden und zusätzlich CSS-Module reagieren für Klassennamen Mapping.

Auf diese Weise können Sie Ihre Stile wie folgt importieren und normales CSS verwenden, das lokal für Ihre Komponenten gilt:

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

Hier ist ein Beispiel für Webpack-CSS-Module

svnm
quelle
Zu Ihrer Information: Wenn Sie Meteor verwenden, lesen Sie dieses Paket: github.com/nathantreid/meteor-css-modules . Ich benutze es selbst und habe bisher großen Erfolg.
Spiralis
Dies ist eine großartige Möglichkeit, reaktionsfähige Komponenten zu formatieren, bietet Ihnen jedoch nicht die gesamte Kontrolle über Inline-Stile. Zum Beispiel können Sie :hoverStile zur Laufzeit nicht wie mit Radium oder einer anderen onMouseOverbasierten Lösung ändern
Charlie Martin
4

onMouseOver und onMouseLeave mit setState schienen mir zunächst ein wenig Overhead zu sein - aber so wie Reagieren funktioniert, scheint es mir die einfachste und sauberste Lösung zu sein.

Das Rendern einer themenbezogenen CSS-Serverseite ist beispielsweise auch eine gute Lösung und hält die Reaktionskomponenten sauberer.

Wenn Sie keine dynamischen Stile an Elemente anhängen müssen (z. B. für ein Thema), sollten Sie überhaupt keine Inline-Stile verwenden, sondern CSS-Klassen.

Dies ist eine traditionelle HTML / CSS-Regel, um HTML / JSX sauber und einfach zu halten.

lukas gurschler
quelle
4

Der einfache Weg ist die Verwendung eines ternären Operators

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>
    )
  }
Hemadri Dasari
quelle
1

Bei Verwendung der Haken:

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>
  );
};
Jaroslav
quelle
0

Ich verwende hierfür eine ziemlich hackige Lösung in einer meiner jüngsten Anwendungen, die für meine Zwecke geeignet ist, und finde sie schneller als das Schreiben von benutzerdefinierten Funktionen für Schwebeeinstellungen in Vanilla JS (obwohl ich erkenne, dass dies in den meisten Umgebungen möglicherweise keine bewährte Methode ist ..) Also, falls Sie noch interessiert sind, hier geht's.

Ich erstelle ein übergeordnetes Element, nur um die Inline-Javascript-Stile zu speichern, und dann ein untergeordnetes Element mit einem Klassennamen oder einer ID, an die sich mein CSS-Stylesheet anschließt, und schreibe den Hover-Stil in meine dedizierte CSS-Datei. Dies funktioniert, weil das detailliertere untergeordnete Element die Inline-js-Stile über die Vererbung empfängt, die Hover-Stile jedoch von der CSS-Datei überschrieben werden.

Im Grunde genommen existiert meine eigentliche CSS-Datei nur zum Halten von Hover-Effekten, sonst nichts. Dies macht es ziemlich übersichtlich und einfach zu verwalten und ermöglicht es mir, das Schwerheben in meinen Inline-React-Komponentenstilen durchzuführen.

Hier ist ein Beispiel:

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>

Beachten Sie, dass für den Inline-Stil "Kind" keine Eigenschaft "Farbe" festgelegt ist. In diesem Fall würde dies nicht funktionieren, da der Inline-Stil Vorrang vor meinem Stylesheet hat.

Witygass
quelle
0

Ich bin mir nicht 100% sicher, ob dies die Antwort ist, aber es ist der Trick, mit dem ich den CSS simuliere: Hover-Effekt mit Farben und Bildern inline.

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

Vor dem Schweben

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

Beim Schweben

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

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

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

Wo schwebbar definiert ist als:

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 : {})
  });
}
Sig
quelle