(续)Css in js 一次实践

498 阅读3分钟

前言

在上一章css in js 一次实践中的末尾留了三个彩蛋:

1、styled.div & styled('div') 有什么区别

2、模版字符串中的样式是怎么解析的?为什么可以嵌套?

3、为什么会返回一个组件?

本章就从源码来简单解释一下。

第一个问题

先看包里的package.json,找到main字段

按照这个路径去找入口,并没有找到,如果有哪位小伙伴找到了,记得和我说一下。 既然主入口没找到,那就去src下面的index里找找看
进入这个文件,源码是

// @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包里导出的

type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;

对应了React中两种组件的定义方式(类定义和纯函数定义)。接着看,注释上说

对所有有效的html元素建立快捷键,这个docElements里定一个所有的html元素,遍

历这个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能力。

最后,如果我有写的不对的地方,欢迎指正,谢谢。

祝生活愉快。