在样式化组件中子组件的输入焦点上设置父组件的样式

问题描述 投票:0回答:4

我已经看到了这个问题的一些繁琐的解决方案,在 React 中使用 refs 或事件处理程序。我想知道样式组件中是否有解决方案。

下面的代码显然是不正确的。当我的输入子组件具有焦点时,我试图找出设置父组件样式的最简单方法。使用样式组件可以吗?

解决这个问题的最佳方法是什么,特别是考虑到样式组件,即使这意味着依赖上面提到的 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';
  }
`;
javascript reactjs styled-components
4个回答
11
投票

看看

:focus-within
!我想这正是您正在寻找的。

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


5
投票

//2022 年更新:

您可以使用

:focus-within
(感谢您弄清楚@hoodsy)

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


//原答案(需要IE和Edge支持):

遗憾的是,无法仅根据纯 CSS/样式组件的子状态来选择父级。虽然它是 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>

这样您就可以更好地控制组件,并可以更轻松地决定将焦点/模糊状态传递给其他元素。


1
投票

@hoodsy 谢谢,它就像我在父 div 上使用的一个魅力一样,当输入聚焦时改变标签的颜色。

     &:focus-within label{
      color: blue;
  }

0
投票

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>

© www.soinside.com 2019 - 2024. All rights reserved.