1. 为什么会有CSS-IN-JS
CSS-IN-JS是web项目中将css代码捆绑在javascript代码中的解决方案,这种方案旨在解决css的局限性,例如缺乏动态功能,作用域和可移植性。
2. CSS-IN-JS介绍
优点:
- 让CSS代码拥有独立的作用域,阻止CSS代码泄露到组件外部,防止样式冲突。
- 让组件更具可移植性,实现开箱即用,轻松创建松耦合的应用程序。
- 让组件更具可重用性,只需编写一次即可,可以在任何地方运行.不仅可以在同一-应用程序中重用组件,而且可以在使用相同框架构建的其他应用程序中重用组件。
- 让样式具有动态功能,可以将复杂的逻辑应用于样式规则,如果要创建需要动态功能的复杂UI,它是理想的解决方案
缺点:
- 为项目增了了额外的复杂性
- 自动生成的选择器大大降低了代码的可读性
优点 > 缺点
3. Emotion 库
以react为例:
Emotion是一个旨在使用jsvascript编写css样式的库
npm install @emotion/core @emotion/styled
- babel配置以支持css属性的两种方式
方案1.
css属性支持
/** @jsx jsx */
: 通知babel,不用再将jsx语法转换成React.createElement方法,而是需要转换为jsx方法
// 必须这样写
/** @jsx jsx */
import { jsx } from '@emotion/core'
function App() {
return <div css={{width:200, height: 200, background: 'red'}}>app works</div>
}
export default App
方案2.
- npm run eject (项目需要加入到git仓库, 可以弹射出项目底层配置)
- npm install @emotion/babel-preset-css-prop
- 在package.json文件中找到babel属性,加入如下内容:
"babel": {
"presets": [
"react-app",
"@emotion/babel-preset-css-prop"
]
}
4. 这样就可以正常解析了
function App() {
return <div css={{width:200, height: 200, background: 'red'}}>app works</div>
}
export default App
3.2 css方法的使用方式
- string styles
const style = css`
width: 100px;
height: 100px;
background: red;
`
<div css={style}>app workds</div>
- Object styles
const style= css({
width: 200,
height:200,
background: 'red'
})
<div css={style}>app workds</div>
3.3 css属性优先级
props对象中的css属性优先级高于组件内部的css属性。
在调用组件时可以在覆盖组件默认样式。
- 验证:props对象中的css属性优先级高于组件内部的css属性。
// css.js
import React from 'react'
import {css} from '@emotion/core'
const style = css`
width: 200px;
height: 200x;
background: skyblue
`
function Css(){
return <div css={style} {...props}>
css
</div>
}
export default Css
import Css from './css.js'
const style=css`
background: pink
`
function App(){
return <div >
<Css css = {style}/>
</div>
}
export default App
- 最后浏览器中是pink色。
3.4 创建样式化组件
Style Components样式化组件
样式化组件:就是用来构建用户界面的,是emotion库提供的另外一种为元素添加样式的方法。
1.创建样式化组件
import styled from '@emotion/styled'
// 1.string styles
// 创建Button组件,首字母必须大写
// 创建button对应的样式化组件
const Button = styled.button`
color: red,
width: 100px;
height:20px;
`
// 2.object styles
// 创建div对应的样式化组件
const Container = styled.div({
width: 100,
background: pink,
margin: '0 auto'
})
// 使用组件
function App(){
return <div >
<Button>我是按钮</Button>
<Container>我是container组件</Container>
</div>
}
export default App
3.5 样式化组件默认样式的覆盖方式
根据props属性覆盖样式
1.string styles
const Button = styled.button`
width: 100px;
height:20px;
background: ${props => props.bgColor || 'skyblue'}
`
2.obejct styles
const Container = styled.div(props=> ({
width: props.w || 1000,
background: pink,
margin: '0 auto'
}))
案例:
import styled from '@emotion/styled'
// 1.string styles
// 创建Button组件,首字母必须大写
// 创建button对应的样式化组件
const Button = styled.button`
color: red,
width: 100px;
height:20px;
backgroun: ${props => props.bgColor || 'skyblue' }
`
// 2.object styles
// 创建div对应的样式化组件
const Container = styled.div(props => (
{
width: props.w || 1000,
background: pink,
margin: '0 auto'
}
))
// 使用组件
function App(){
return <div >
<Button bgColor="pink">我是按钮</Button>
<Container w={1600}>我是container组件</Container>
</div>
}
export default App
3.6 为任何组件添加样式
const Demo = ({classname}) => <div classname={classname}>demo</div>
// 1.string styles
const Facy = styled(Demo)`
color: red;
`
// 2.obejct styles
const Facy2 = styled(Demo)({
background: 'tomato',
color: 'white'
})
function App(){
return <div >
<Facy/>
<Facy2/>
</div>
}
export default App
3.7 通过父组件设置子组件样式
1.string styles
const Child = styled.div`
color: red
`
const Parent = styled.div`
${Child} {
color: green
}
`
- object styles
const Child = styled.div({
color: 'red'
})
const Parent = styled.div({
[Child] :{
color: 'green'
}
})
案例
const Child = styled.div`
color: red
`
const Parent = styled.div`
${Child} {
color: green
}
`
function App() {
return (
<>
<Parent>
<Child> parent child </Child>
</Parent>
</>
)
}
3.8 css选选择器 &
嵌套选择器 & , & 表示组件本身
// 这里的 & 表示:div
// 通过 & 可以找到这个元素的子元素,然后再添加一些样式
const Container = styled.div`
color: red;
& > a {
color: pink
}
`
案例:
const Container = styled.div`
width: 200px;
height: 200px;
background: skyblue;
color: pink;
& :hoveer{
background: pink;
}
& > span{
color: yellow
}
`
function App() {
return (
<>
<Container>
Container
<span>span</span>
</Container>
</>
)
}
3.9 as 属性
as: 要使用组件中的样式,但要更改呈现的元素
const Button = styled.button`
color: red
`
// 把Button组件当作a标签来使用
<Button as="a" href="#"></Button>
3.10样式组合
在组合样式中,后调用的样式优先级高于先调用的样式。
const base = css`
color: yellow
`
const danger = css`
color: red
`
<button css={[base, danger]}>button</button>
// 最终只会有一个样式。取决于调用顺序,后调用的样式优先级高于先调用的样式。
// danger > base
3.11 Global 组件
定义全局样式
import {css, Global} from '@emotion/core'
const styles =css`
body {
margin: 0
}
`
function App() {
return (
<>
<Global styles={styles}>
app works
</Global>
</>
)
}
3.12 创建主题
1.下载主题模块 npm install emotion-theming
2.引入ThemeProvider 组件
import {ThemeProvider} from ' emotion-theming'
- 将ThemeProvider放置在视图最外层
function App(){
return (
<>
<ThemeProvider></ThemeProvider>
</>
)
}
- 添加主题内容
const theme = {
colors: {primary: 'hotpink'}
}
<ThemeProvider theme={theme}></ThemeProvider>
- 获取主题内容(方案1)
const getPrimaryColor = props => css`
color: ${props.colors.primary}
`
<div css={getPrimaryColor}></div>
- 获取主题内容(方案2)
import {useTheme} from 'emotion-theming'
function Demo() {
const theme = useTheme()
}
案例:
index.js
import {ThemeProvider} from ' emotion-theming'
import ReactDom from 'react-dom'
const theme = {
colors: {
primary: 'tomato'
}
}
ReactDom.render(
<ThemeProvider theme={theme}>
<App/>
</ThemeProvider>
, document.getElementById('root')
)
App.js
import {css} from '@emotion/core'
// 方案2:获取和主题内容
import {useTheme} from 'emotion-theming'
// 方案1:获取和主题内容
const primaryColor = props => css`
color: ${props.colors.primary}
`
function App() {
console.log(useTheme)
return (
<div css={primaryColor}></div>
)
}
export default App