如何 select 样式组件中的父组件变体?

How to select parent components variant in styled components?

styled-components 中,我们可以使用 component selector pattern 添加上下文样式。但是我们如何 select 特定的父变体来根据上下文设置子组件的样式?例如,我们这里有三个组件,ChildNoteWrapperNote.

const Child = styled.div<{ editing?: boolean }>`
  ${props => props.editing && css`some styles`}
`

const NoteWrapper = styled.div<{ compact?: boolean }>`
  ${props => props.compact && css`some styles`}
`

const Note = styled.input`

/* How do I style this when Child is editing and NoteWrapper is compact */

`

const App = () => {
  return (
   <Child editing>
    <NoteWrapper compact>
     <Note/>
    </NoteWrapper>
   </Child>
  )
}

`

使用普通 CSS 我们可以做这样的事情


.child.editing .note-wrapper.compact .note {
  /* Contextual styles here */
}

我知道我可以轻松使用 editingcompact 变量并将其传递给 Note 组件。但是,如果组件高度嵌套,就很难做到。

我的问题是当 Childediting 并且 NoteWrappercompactNotestyled-components select或模式?

我认为我们不能以某种方式在 styled-components 中做这样的事情?我们可以吗?

const Note = styled.input`
 ${Child.editingClass} ${NoteWrapper.compactClass} & {
  /* The contextual styles here*/
 }
`

据我所知,您无法访问 editingcompact,因为它们是道具,不会在 CSS 中“传播”。但是您可以使用 classes 或数据属性获得相同的结果。

这是我的做法:

const App = () => {
  return (
  <Child data-editing={true}>
    <NoteWrapper data-compact={true}>
      <Note/>
    </NoteWrapper>
  </Child>
  )
}

const Child = styled.div`
`

const NoteWrapper = styled.div`
`

const Note = styled.input`
  ${Child}[data-editing="true"] ${NoteWrapper}[data-compact="true"] & {
    /* 
      Only applied when Child is editing and NoteWrapper is compact
    */
    color: red;
  }

`

本质上,styled-components 需要在一天结束时产生有效的 CSS。 ${Child} 将替换为自定义生成的 class 名称,例如 .sc-abc123。所以最终结果是 .sc-abc123[data-editing="true"],这是完全有效的 CSS.

你也可以使用 classes,它看起来更简洁:

const App = () => {
  return (
  <Child className="editing">
    <NoteWrapper className="compact">
      <Note/>
    </NoteWrapper>
  </Child>
  )
}

const Child = styled.div`
`

const NoteWrapper = styled.div`
`

const Note = styled.input`
  ${Child}.editing ${NoteWrapper}.compact & {
    /* 
      Only applied when Child is editing and NoteWrapper is compact
    */
    color: red;
  }

`

我更喜欢使用数据属性,因为很明显它们用于逻辑目的,而不是因为 editing 是 CSS class 和一堆样式。但这是一种主观偏好,它们在 objective 功能方面都同样出色:)

您也可以将道具传递给 Note 组件本身并进行类似的逻辑检查。

<Note
  compactEdit={editing && compact}
/>

const Note = styled.div`
  ${props =>
    props.compactEdit
      ? css`color: red;`
      : css`color: blue;`
    };
`;