styled-components 深入浅出 (一) : 基础使用

389 阅读4分钟

前言

styed-components 是一个基于 JavaScript 的样式库,它通过标签模板字符串的方式样式化组件,它允许我们使用 JavaScript 直接编写 CSS 样式,并且样式是组件级隔离。在网上找中文相关的资料不是很多,貌似国内用这个不多,于是我就根据我的使用经历记录一下如何使用这个库,以及和大家一起解读一下源代码是如何实现的。该知识将分为多篇文章分享记录。ps: 以下代码例子都经过我实测!

所有相关文章:

《styled-components 深入浅出 (一) : 基础使用》

《styled-components 深入浅出 (二) : 高阶组件》

《styled-components 深入浅出 (三) : 源码解析》

基础用法

首先导入模块 styled-components, import styled from 'styled-components'

然后我们可以通过这个 styled 函数创建 React组件(component) 或标签(tagname)。既然创建的是 React 组件,使用的时候当做普通的 React 组件使用就行了。

通过 styled.tagname 这种标签模板字符串的语法来创建样式化组件,其中 tagname 就是 html 的标签名。

创建自定义样式化标签

  const Button = styled.button`
    background: blue;
    border-radius: 3px;
    border: none;
    color: white;
  `
<Button>Click Me</Button>

样式化组件的样式可以被继承,也可以被覆盖

  const Button = styled.button`
    background: blue;
    border-radius: 3px;
    border: none;
    color: white;
  `

  const TomatoButton = styled(Button)`
    background: tomato;
  `
<Button>Click Me</Button>
<TomatoButton>Click Me</TomatoButton>

通过传参创建动态样式

const padding = '10px'
export const Section = styled.section`
  color: white;

  /* ES 的插值语法引入变量 */
  padding: ${padding};

  /* 通过组件props 传参 */
  background: ${props => props.$background};
`

使用的时候传入 background 参数即可

<Section $background={'red'}>
  Section
</Section>

注意:使用 ES 的插值语法时,不支持 伪类选择器、媒体查询、嵌套等!

注意:带 $ 的参数是临时属性(Transient props)不会作用底层 React 节点或渲染到 DOM 元素,而是仅作为插值函数的参数。

styledComponent(样式化组件)可以像普通的React组件一样使用任何属性,如果该属性是有效属性,便会作用于 HTML 节点,否则仅作为插值函数的参数。

export const MyInput = styled.input`
  border: 1px red solid;
  padding:${props => props.padding};
`
<MyInput type={"password"} padding={'10px'}></MyInput>

用 .attrs 给样式化组件添加属性值

styled-components 允许你给样式化组件添加属性,这些属性会作用于组件的 HTML 节点,而不是作为插值函数的参数,

注意:.attrs 方法只接受一个参数,即样式化组件的静态属性对象或者是一个返回属性对象的函数。

在平常开发中,通常有这么几种使用方式

  • 设置默认属性 添加通用样式
export const MyInput = styled.input.attrs({
  type: 'password',
  style: {
    padding: '10px'
  }
})`
  border: 1px red solid;
`
<MyInput></MyInput>
  • 动态计算属性值

用函数属性来根据组件的 props 动态计算属性值。基于不同条件给组件添加属性值

export const MyButton = styled.button.attrs(props => ({
  style: {
    backgroundColor: props.variant === 'primary' ? 'blue' : 'gray'
  }
}))
  `
    color: white;
    padding: 10px 20px;
    border: none;
    cursor: pointer;
  `
<MyButton variant='primary'>主题按钮</MyButton>
  • 提供默认交互行为
export const MyButton = styled.button.attrs(props => ({
  style: {
    backgroundColor: props.variant === 'primary' ? 'blue' : 'gray'
  },
  onClick: () => console.log('Button clicked!'),
}))
  `
    color: white;
    padding: 10px 20px;
    border: none;
    cursor: pointer;
  `
<MyButton variant='primary'>主题按钮</MyButton>

多态属性(polymorphic prop) as

多态属性是指你可以在组件中通过一个属性来控制最终渲染的 HTML 元素类型或自定义组件类型。

比如我们写导航栏组件的时候,有些是菜单栏,有些是按钮,有些是链接,但所有的样式都相同,这时候我们可以通过这个多态属性来控制最终渲染成什么html标签或者自定义组件。

  • 使用多态属性动态创建标签
export const Component = styled.div`
  font-family: "Microsoft YaHei";
  padding: 10px 10px;
  line-height: 1;
  -webkit-text-decoration: none;
  text-decoration: none;
  font-size: 14px;
  background-color: blue;
  color: white;
  border: none;
  box-sizing: border-box;
  cursor: pointer;
`;

// 这个样式化组件最终会渲染成 a 标签
<Component as="a" href="https://www.baidu.com">button</Component>
<br/>
// 这个样式化组件最终会渲染成 button 标签
<Component
  as="button"
  onClick={() => alert('这是个按钮')}
>
  button
</Component>
  • 使用 forwardedAs 属性来传递被包裹组件的多态属性值。

如果一个组件被另一个或多个组件包裹着,外层组件可以通过 forwardedAs 属性来传递多态属(as)性值到内部组件。

看下面例子:

export const Component = styled.button`
  font-family: "Microsoft YaHei";
  padding: 10px 10px;
  line-height: 1;
  -webkit-text-decoration: none;
  text-decoration: none;
  font-size: 14px;
  background-color: blue;
  color: white;
  border: none;
  box-sizing: border-box;
  cursor: pointer;
`;

export const WrappedButton = (props) => {

  return <div>
    <Component {...props} />
  </div>;
}


// 使用 styled() 高阶组件包装 Component,并传递 as 属性
const WrappedComponent = styled(WrappedButton)`
  /* 这里可以添加额外样式 */
`;
<WrappedComponent forwardedAs="a" href="https://www.baidu.com">
  Wrapped Link Button
</WrappedComponent>

控制属性传递(属性过滤器)

默认情况下,所有被包裹组件的属性值都会被传递到内部组件。而临时属性不会传递到最终渲染的 react 组件上。那假如我需要动态控制某些属性值能不能传递到最终渲染的 react 组件上时,就可以通过 shouldForwardProp 属性来控制。可以它当做一个属性过滤函数,类似 Array.filter 方法。

export const Comp = styled('div').withConfig({
  shouldForwardProp: (prop) => !['customProp'].includes(prop),
})`
  color: ${props => props.color};
`;
  <Comp color='red' customProp="test">hello</Comp>

注意:这里面的变量color不能使用临时属性(带$的属性),临时属性的值是不会传递到最终渲染的组件上

下篇文章将介绍一些 styled component 的高阶组件,例如如何创建主题样式、如何获取主题样式、如何创建全局样式,如何创建动画等等。

写在最后

我是 AndyHu,目前暂时是一枚前端搬砖工程师。

文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注呀😊

未经许可禁止转载💌

speak less,do more.