在上一章css in js 一次实践中的末尾留了三个彩蛋:css
一、styled.div & styled('div') 有什么区别html
二、模版字符串中的样式是怎么解析的?为何能够嵌套?react
三、为何会返回一个组件?es6
本章就从源码来简单解释一下。json
先看包里的package.json,找到main
字段bash
// @flow
import type { Target } from '../types'
import domElements from '../utils/domElements'
export default (styledComponent: Function, constructWithOptions: Function) => {
const styled = (tag: Target) => constructWithOptions(styledComponent, tag)
// Shorthands for all valid HTML Elements
domElements.forEach(domElement => {
styled[domElement] = styled(domElement)
})
return styled
}
复制代码
能够看到,函数内定义了一个styled函数,接收一个Target类型的参数,这个Target类型定义是export type Target = string | ComponentType<*>
,而这个ComponentType就是从react包里导出的dom
type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
函数
对应了React中两种组件的定义方式(类定义和纯函数定义)。接着看,注释上说post
对全部有效的html元素创建快捷键,这个docElements里定一个全部的html元素,遍ui
历这个docElements元素,将html元素添加为styled对象的属性。至于这句
styled(domElement)
你们别忘了上面Target的类型定义里前面还能够接收一个string
类型参数。至此,
第一个问题解决,styled.div 和 styled('div')没有任何区别,styled.div只是style('div')的
快捷方式,可是 style.
形式的使用只支持html元素,对React组件不适用,
因此,在为组件定义样式的时候仍是使用styled(ReactComponent)。
ES6里标签模版的形式,函数即标签,模版紧跟在标签后面做为标签的参数,也就是styled.div后面的模版字符串里的内容做为style.div函数的参数调用。 具体关于模版字符串的内容请参考阮一峰的ES6模版字符串
关于styled解决css嵌套问题,先贴一下css.js的代码:
// @flow
import interleave from '../utils/interleave'
import isPlainObject from '../utils/isPlainObject'
import { EMPTY_ARRAY } from '../utils/empties'
import flatten from '../utils/flatten'
import type { Interpolation, RuleSet, Styles } from '../types'
export default (
styles: Styles,
...interpolations: Array<Interpolation>
): RuleSet => {
if (typeof styles === 'function' || isPlainObject(styles)) {
// $FlowFixMe
return flatten(interleave(EMPTY_ARRAY, [styles, ...interpolations]))
}
// $FlowFixMe
return flatten(interleave(styles, interpolations))
}
复制代码
css这个函数是做为一个参数供style对象调用的,由于之间的关系太深,没办法贴出来,有兴趣的小伙伴能够本身去看一下。
能够看到css.js返回了一个flatten函数,字面意思是拉伸、变平。这个函数的做用就是把嵌套的css变为一层,Array.flat()函数。
其实第三个问题你们应该都能想到,没错,就是HOC(高阶组件),利用高阶组件的Prop将style传递给children,相似于这种:
const StyledComponent = (options) => (Target) => {
return class extends React.Component{
static displayName = ...(styled.Target)
render(){
const {styles} = options;
const props = Object.assign({},this.props,{style:styles})
return <Target {...props}/>
}
}
}
复制代码
时间仓促,并无将这个包很详细的讲一下(其实我不会。。。),这个包里还有不少很好玩的东西,好比观察者模式、发布订阅模式、once函数、curry函数等等。写这篇的主要目的就是想要看看一个包是怎么实现的,它里面用到的思想和技巧可以对咱们产生很大的启发,因此我建议小伙伴们在使用一个第三方的时候尽量的去看看人家是怎么实现的?为何这么实现?这能快速提升咱们的思惟方式和coding能力。
最后,若是我有写的不对的地方,欢迎指正,谢谢。
祝生活愉快。