iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0
Modern Web

用React刻自己的投資Dashboard系列 第 24

用React刻自己的投資Dashboard Day24 - styled components

tags: 2021鐵人賽 React

因為下一篇要讓導覽列在手機版網頁呈現漢堡選單的樣式,在參考其他工程師寫的網頁的時候,發現有一位是用styled-components這個套件來寫的,這篇就來了解styled-components的特色,以及學習怎麼使用它。

CSS in JS

就是可以把CSS寫在JS裡面的意思,這樣的寫法好處是寫在JS裡面的CSS設定,只會對這支JS產生的HTML元素有效果,不會影響到別支JS檔產生的元素。這跟之前的CSS module有類似的作用,不過styled-components還有許多CSS module沒有的特點,下面會再一一說明。
下面這個是CSS in JS的簡單範例,也可以到codepen連結玩玩:

const Container = styled.div`
  text-align: center;
`

const Button = styled.button`
  border-radius: 3px;
  border: 2px solid palevioletred;
  color: palevioletred;
  margin: 0 1em;
  padding: 0.25em 1em;
`

function App() {
  return (
    <Container>
      <Button>Normal Button</Button>
    </Container>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

Props

可以透過props將變數傳遞至CSS樣式內,官方範例如下,或是可以至codepen玩玩,看到button會出現兩種背景不同樣式,因為一個有加primary。這個功能我覺得還蠻好用的,可以根據載入JSX元件的資料動態改變CSS設定,例如股票的漲跌就會用到,數字大於0就用紅色,數字小於0就用綠色...之類的用法。不過要記得import { css }喔。

const Container = styled.div`
  text-align: center;
`

const Button = styled.button`
  background: transparent;
  border-radius: 3px;
  border: 2px solid palevioletred;
  color: palevioletred;
  margin: 0 1em;
  padding: 0.25em 1em;

  ${props =>
    props.primary &&
    css`
      background: palevioletred;
      color: white;
    `};
`

function App() {
  return (
    <Container>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </Container>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

{ css }

前一個範例有import { css },這是CSS的helper,當有常用的css設定,就可以把它寫成一個helper,就可以重複使用了,因此可以將上一個範例程式碼改成這樣,props的部份就變得比較簡潔。

const Container = styled.div`
  text-align: center;
`

const Button = styled.button`
  background: transparent;
  border-radius: 3px;
  border: 2px solid palevioletred;
  color: palevioletred;
  margin: 0 1em;
  padding: 0.25em 1em;

  ${props =>
    props.primary && helper
`

const helper = 
    css`
      background: palevioletred;
      color: white;
    `

function App() {
  return (
    <Container>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </Container>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

Extending Styles

這個功能是可以用已經寫好的styled components去製作新的components,樣式會承接之前寫好的部分,然後還可以加上新的樣式,可以到codepen玩玩。

const Container = styled.div`
  text-align: center;
`

const Button = styled.button`
  background: transparent;
  border-radius: 3px;
  border: 2px solid palevioletred;
  color: palevioletred;
  margin: 0 1em;
  padding: 0.25em 1em;
`

const GreenButton = styled(Button)`
  color: green;
  border-color: green;
`;

function App() {
  return (
    <Container>
      <Button>Normal Button</Button>
      <GreenButton>Primary Button</GreenButton>
    </Container>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

Theming

這個功能非常強大,使用方式是透過ThemeProvider這個wrapper component,將主題樣式套用在所有在wrapper內的styled-components,而且不管子元件在多深的階層都能套用到。範例可至codepen玩玩。

const Container = styled.div`
  text-align: center;
`

const Button = styled.button`
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border-radius: 3px;

  /* Color the border and text with theme.main */
  color: ${props => props.theme.main};
  border: 2px solid ${props => props.theme.main};
`;

const Link = styled.a`
  font-size: 1em;
  color: ${props => props.theme.deeper};
`

Button.defaultProps = {
  theme: {
    main: "palevioletred"
  }
}

const theme = {
  main: "mediumseagreen",
  deeper: "palevioletred"
};

function App() {
  return (
    <Container>
      <Button>Normal</Button>
      <ThemeProvider theme={theme}>
        <Button>Themed</Button>
        <Button><Link>Deeper</Link></Button>
      </ThemeProvider>
    </Container>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

小結

styled-components是個非常強大的套件,可以使用的功能還蠻多的,今天寫的只是其中一小部份,不過這些暫時先足夠拿來製作漢堡選單,下一篇就會開始來製作導覽列的漢堡選單囉。


上一篇
用React刻自己的投資Dashboard Day23 - 非同步呼叫API,完成首頁資料串接
下一篇
用React刻自己的投資Dashboard Day25 - 製作漢堡選單
系列文
用React刻自己的投資Dashboard30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言