citrus327/issue-blog-record

React学习与探索之路 (三) - Dark Mode with Styled Components

Closed this issue · 0 comments

React学习与探索之路 (三) - Dark Mode with Styled Components

一点想法

看到 Styled Components 文档里的一些高级特性,其中有一项是ThemeProvider,便萌生出使用他完成类似之前IOS上Night Shift的功能,也就是Dark Mode.

实现

放置ThemeProvider

Dark Mode影响的范围应该涉及 Login 页面以及 Dashboard. 所以ThemeProvider应该在这2个组件之上。

<ThemeProvider theme={this.state.theme}>
  {
    isAuthenticated ? <Login/> : <Dashboard/>
  }
</ThemeProvider>

theme对象目前会有一个dark的Boolean属性对Dark Mode进行控制,UI层面上会提供一个Switch来进行模式的切换

Dark Mode的状态管理

this.state.theme = {
  dark: false
}

// 定义handleDarkModeChange函数
handleDarkModeChange () {
  this.setState((prev) => {
    return {
      theme: {
        dark: !prev.theme.dark
      }
    }
  })
}

render () {
  return (
    // 传入子组件
    <ThemeProvider theme={this.state.theme}>
      {
        isAuthenticated ? 
          <Login handleDarkModeChange={this.handleDarkModeChange}/> : 
          <Dashboard handleDarkModeChange={this.handleDarkModeChange}/>
      }
    </ThemeProvider>
  )
}

Dark Mode 的 CSS 实现

在样式方面,使用Styled Component的传参功能对样式进行修改

const StyledDashboardRoot = styled(StyledDiv)`
  color: ${props => props.theme.dark ? 'white' : 'black'};
  background-color: ${props => props.theme.dark ? '#f7f7f7' : '#282c34'};
  transition: background-color 200ms linear, color 200ms linear;
  ...略

  .MuiListItemIcon-root {
    color: ${props => props.theme.dark ? 'white' : 'black'};
  }

  .MuiListSubheader-root {
    color: ${props => props.theme.dark ? 'white' : 'black'};
    opacity: 0.8;
  }

  .MuiDivider-root {
    background-color: ${props => props.theme.dark ? '#f7f7f7' : undefined};
    opacity: ${props => props.theme.dark ? '0.1' : undefined};
  }

  .dashboard-main {
    background-color: ${props => props.theme.dark ? '#282c34' : '#f7f7f7'};
    height: 100%;
    ...略
  }
`

大致的实现就是黑暗模式下,背景色为暗色,主色调为亮色。�

使用Switch组件控制Dark Mode

<Switch
  checked={this.props.theme.dark}
  onChange={(event) => this.props.handleDarkModeChange(event.target.value)}
  color="default"
  size="small"
/>

可以看到这里的theme是从this.props里读取的,那也就是theme对象需要注入到组件级别,这里可以使用Styled-Components库提供的withTheme的高阶组件

withTheme(Navbar)

以上涉及了Provider的概念,具体Styled Components的传参功能,ThemeProvider和withTheme HOC的运用。