Я видел некоторые обременительные решения этой проблемы, используя ссылки или обработчики событий в React. Мне интересно, есть ли решение вообще в styleled-компонентах.

Код ниже явно неверный. Я пытаюсь выяснить самый простой способ стилизации моего родительского компонента, когда мой входной дочерний компонент имеет фокус. Возможно ли это с помощью стилевых компонентов?

Как лучше всего это сделать, особенно с учетом стилевых компонентов, даже если это означает использование одного из методов React, упомянутых выше?

const Parent = () => (
  <ParentDiv>
    <Input/>
  </ParentDiv>
);


const ParentDiv = styled.div`
  background: '#FFFFFF';

  ${Input}:focus & {
    background: '#444444';
  }
`;

const Input = styled.input`
  color: #2760BC;

  &:focus{
    color: '#000000';
  }
`;
3
twils0 30 Авг 2017 в 16:55

3 ответа

Лучший ответ

Проверьте :focus-within! Я думаю, что это именно то, что вы ищете.

https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within

5
hoodsy 12 Июл 2018 в 22:42

// обновление 2018:

Если вам не нужна поддержка Edge или IE, вы можете использовать :focus-within (спасибо за выяснение @hoodsy)

div:focus-within {
  background: #444;
}
<div>
  <input type="text" />
</div>

// оригинальный ответ (с поддержкой IE и Edge) :

К сожалению, нет способа выбрать родителя, основываясь только на состоянии ребенка с чистыми CSS / styled-компонентами. Хотя это рабочий проект в CSS4, в настоящее время ни один браузер не поддерживает его. Подробнее об этом здесь.

Я обычно добавляю атрибут onFocus и onBlur в поле ввода, который затем вызывает изменение состояния. В вашем случае у вас есть компонент без сохранения состояния. Поэтому вы можете использовать innerRef для добавления или удаления класса из родительского. Но я думаю, вы уже нашли это решение. Тем не менее я выложу это также:

const styled = styled.default;

const changeParent = ( hasFocus, ref ) => {
  // IE11 does not support second argument of toggle, so...
  const method = hasFocus ? 'add' : 'remove';
  ref.parentElement.classList[ method ]( 'has-focus' );
}

const Parent = () => {
  let inputRef = null;
  
  return (
    <ParentDiv>
      <Input
        innerRef={ dom => inputRef = dom }
        onFocus={ () => changeParent( true, inputRef ) }
        onBlur={ () => changeParent( false, inputRef ) }
      />
    </ParentDiv>
  );
};

const ParentDiv = styled.div`
  background: #fff;

  &.has-focus {
    background: #444;
  }
`;

const Input = styled.input`
  color: #2760BC;

  &:focus{
    color: #000;
  }
`;

ReactDOM.render( <Parent />, document.getElementById( 'app' ) );
<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>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>

<div id="app"></div>

Более жесткий метод - преобразовать Parent в класс, чтобы вы могли использовать состояния:

const styled = styled.default;

class Parent extends React.Component {
  state = {
    hasFocus: false,
  }
  
  setFocus = ( hasFocus ) => {
    this.setState( { hasFocus } );
  }
  
  render() {
    return (
      <ParentDiv hasFocus={ this.state.hasFocus }>
        <Input
          onFocus={ () => this.setFocus( true )  }
          onBlur={ () => this.setFocus( false ) }
        />
      </ParentDiv>
    );
  }
};

const ParentDiv = styled.div`
  background: ${ props => props.hasFocus ? '#444' : '#fff' };

`;

const Input = styled.input`
  color: #2760BC;

  &:focus{
    color: #000;
  }
`;

ReactDOM.render( <Parent />, document.getElementById( 'app' ) );
<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>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>

<div id="app"></div>

Таким образом, вы лучше контролируете свой компонент и можете легко решить передать состояние фокусировки / размытия другим элементам.

2
lumio 10 Окт 2018 в 12:06

@hoodsy спасибо, это работало как талисман, который я использовал как ниже на родительском div, чтобы изменить цвет метки, когда фокус ввода.

     &:focus-within label{
      color: blue;
  }
0
atmosfer 29 Июл 2018 в 18:08