样式化组件中子组件输入焦点的样式父组件

Posted

技术标签:

【中文标题】样式化组件中子组件输入焦点的样式父组件【英文标题】:Style parent component on input focus of child component in styled-components 【发布时间】:2018-02-08 06:51:08 【问题描述】:

我已经看到了一些针对这个问题的繁重解决方案,在 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';
  
`;

【问题讨论】:

【参考方案1】:

查看:focus-within!我认为这正是您想要的。

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

【讨论】:

这可行,但需要注意的是,IE 和 Edge 都不支持此属性。 npm 上有一个不错的小 polyfill 来支持它 - npmjs.com/package/focus-within-polyfill【参考方案2】:

// 2018 年更新:

如果您不需要 Edge 或 IE 支持,您可以使用 :focus-within(感谢您了解 @hoodsy)

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

// 原答案(支持 IE 和 Edge)

遗憾的是,没有办法选择父级,只能基于子级的状态和纯 CSS/样式组件。虽然它是 CSS4 中的工作草案,但目前没有浏览器支持它。 More about this here.

我通常将onFocusonBlur 属性添加到输入字段,然后触发状态更改。在您的情况下,您有一个无状态组件。因此,您可以使用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>

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

【讨论】:

【参考方案3】:

@hoodsy 谢谢,它就像我在父 div 上使用的魅力一样,可以在输入集中时更改标签的颜色。

     &:focus-within label
      color: blue;
  

【讨论】:

以上是关于样式化组件中子组件输入焦点的样式父组件的主要内容,如果未能解决你的问题,请参考以下文章

在 React 中使用样式化组件重叠左侧部分输入

vue.js中子组件触发父组件的方法

15 Vue中子组件样式的绑定和行内样式模版编写

样式化的组件选择上一个兄弟

使用样式化组件将其分配为常量后如何显示背景图像

如何将 CSS 添加到“不是第一个”呈现的样式化组件