Встроенные стили CSS в React: как реализовать: hover?

178

Мне очень нравится встроенный шаблон CSS в React, и я решил использовать его.

Тем не менее, вы не можете использовать :hoverи подобные селекторы. Итак, как лучше всего реализовать выделение при наведении при использовании встроенных стилей CSS?

Одно из предложений от #reactjs - иметь Clickableкомпонент и использовать его следующим образом:

<Clickable>
    <Link />
</Clickable>

ClickableИмеет hoveredсостояние и передает его в качестве реквизита на ссылку. Тем не менее, Clickable(способ, которым я это реализовал) оборачивает Linkв divтак, чтобы он мог установить onMouseEnterи onMouseLeaveк нему. Это делает вещи немного сложнее, хотя (например, spanзавернутый в a divведет себя иначе, чем span).

Есть ли более простой способ?

fhucho
источник
1
Вы абсолютно правы - единственный способ имитировать: селекторы hover и т.д. со встроенными стилями - использовать onMouseEnterи onMouseLeave. Относительно точной реализации этого - это полностью зависит от вас. Чтобы посмотреть на ваш конкретный пример, почему бы не сделать <Clickable/>обертку span?
Крис Хоутон
3
Я бы предложил использовать внешние таблицы стилей вместе с плагином ExtractText Webpack, это поможет вам в более долгой работе, если вы когда-нибудь захотите использовать ServerRender, в противном случае вы можете попробовать Radium github.com/FormidableLabs/radium
abhirathore2006
В настоящее время Styled Component является лучшим решением для моделирования всех возможностей css / scss в реагировании.
Ахмад Бехзади

Ответы:

43

Я в такой же ситуации. Очень похоже на шаблон сохранения стиля в компонентах, но состояние наведения кажется последним препятствием.

Я написал миксины, которые вы можете добавить к своему компоненту, для которого нужны состояния наведения. Этот миксин добавит новое 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
@ abhirathore2006 Radium работает точно так же, и вопрос в том, как это сделать без использования внешней таблицы стилей
Чарли Мартин,
Не имеет ли больше смысла использовать оператор ванильного спреда?
PAT-O-
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
Адам Таттл
3
Реакция @AdamTuttle имеет onFocusсобытие; так что вы могли бы сделать то же самое для , :focusкак :hover, за исключением того, вместо того , onMouseEnterи onMouseLeaveвам нужно будет толькоonFocus
Jonathan
7
Имейте в виду, что этот метод вызывает выполнение в главном потоке, тогда как типичные события CSS обрабатываются намного эффективнее.
Хампус Альгрен
54

Опоздал на вечеринку, но пришел с решением. Вы можете использовать "&", чтобы определить стили для hover nth 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, а не с отдельной таблицей стилей.
Эмми
36
Чувак, взгляни поближе. Это встроенный стиль.
Ярослав
15
Это не работает с React. Вам нужна дополнительная библиотека, такая как styled-components.
Г.Г.
3
Это не работает со встроенным стилем, этот пример вносит путаницу. Если это действительно работает, приведите лучший пример с полным компонентом.
Александр
2
Превосходно! Работает как шарм!
Федор
26

Вы можете использовать Radium - это инструмент с открытым исходным кодом для встроенных стилей с ReactJS. Он добавляет именно те селекторы, которые вам нужны. Очень популярно, зацените - Radium на npm

гироскоп
источник
Я только что наткнулся на этот пост, как бы вы внедрили Radium в следующей ситуации? module.exports = React.createClass({ displayName: 'App',})
1
@Rkhayat Вы можете либо обернуть его, module.exports = Radium(React.createClass({ displayName: 'App',}))либо присвоить классу значение, и добавить @Radiumдекоратор над ним, если упомянуть документы github.com/FormidableLabs/radium#usage
pbojinov
есть еще
одна
11

Полная поддержка CSS - это как раз та причина, по которой огромное количество библиотек CSSinJS делает это эффективно, вам нужно генерировать настоящий CSS, а не встроенные стили. Кроме того, встроенные стили намного медленнее реагируют в большей системе. Отказ от ответственности - я поддерживаю JSS .

Олег Изонен
источник
9

Made Style It - отчасти - по этой причине (из-за несогласия с реализацией других библиотек / синтаксиса и встроенных стилей отсутствует поддержка префикса значений свойств). Поверьте, мы должны иметь возможность просто писать CSS на JavaScript и иметь полностью автономные компоненты 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, и отступ отключен, вероятно, из-за отсутствующей скобки.
Брэдлигсмит
8

В дополнение к ответу Джонатана , вот события, которые охватывают фокус и активные состояния, и использование 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

Что касается styled-components и response-router v4, вы можете сделать это:

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

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

  &:hover {
    color: white;
  }
`

...
<Clickable><Link to="/somewhere">somewhere</Link></Clickable>
Исаак Пак
источник
6

Это может быть хорошим подспорьем для использования встроенного стиля внутри реагирующего компонента (а также с помощью: hover CSS-функции):

...

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

...
tomericco
источник
5

Оформить заказ Typestyle, если вы используете React с Typescript.

Ниже приведен пример кода для: 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>
paibamboo
источник
4

Вы можете использовать модули css в качестве альтернативы и дополнительно реагировать на css-модули. для отображения имен классов.

Таким образом, вы можете импортировать ваши стили следующим образом и использовать обычную 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);

Вот пример модуля CSS c webpack

svnm
источник
К вашему сведению: если вы используете Meteor, проверьте этот пакет: github.com/nathantreid/meteor-css-modules . Я сам пользуюсь им с большим успехом.
Спиралис
Это отличный способ стилизовать реагирующие компоненты, но не совсем дает вам полный контроль над встроенными стилями. Например, вы не можете изменять :hoverстили во время выполнения, как вы можете с помощью Radium или другого onMouseOverрешения на основе
Чарли Мартин,
4

onMouseOver и onMouseLeave с setState поначалу показались мне немного непосильными, но поскольку именно так работает реагирование, мне кажется, это самое простое и чистое решение.

рендеринг тематических css серверов, например, также является хорошим решением и обеспечивает более чистую реакцию компонентов.

если вам не нужно добавлять динамические стили к элементам (например, для создания тем), вам вообще не следует использовать встроенные стили, а вместо этого использовать классы CSS.

Это традиционное правило html / css, позволяющее сохранять html / JSX чистым и простым.

Лукас Гуршлер
источник
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>
    )
  }
Хемадри Дасари
источник
1

С использованием крючков:

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
источник
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>

Обратите внимание, что встроенный стиль дочернего элемента не имеет установленного свойства color. Если это так, это не сработает, потому что встроенный стиль будет иметь приоритет над моей таблицей стилей.

witygass
источник
0

Я не уверен на 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

Рори
источник
0
<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 : {})
  });
}
Sig
источник