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


178

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

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

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

<Clickable>
    <Link />
</Clickable>

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

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


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

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

...

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

...

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>

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


К вашему сведению: если вы используете 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>
  );
};

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. Если это так, это не сработает, потому что встроенный стиль будет иметь приоритет над моей таблицей стилей.


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 : {})
  });
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.