这是我参加第五届青训营伴学笔记创作活动的第4天。
从ElementPlus源码分析Button的实现(一)
最近在尝试开发组件库。因为用到的技术是Vue,所以参考了比较热门的ElementPlus项目。接下来从源码分析这个Button如何实现。
button的源码主要在/packages/components/button/src
中,其中button.vue
就是这个组件的本体了。
Button的动态分配类名
从标签上来看,button的类名是由一个名为ns的对象,动态赋予类名。如果使用过ElementPlus,会发现button有3个el-
开头的类名,即el-button, el-button-颜色, el-button-大小
。后面两个类名是由组件的type属性和size属性来动态分配的。
ns是由编写的useNamespace
钩子函数获得的命名空间,会获得一个以el-
开头的名字,然后由bem命名规范,为组件动态赋值类名。ns里还有个is方法,判断它是否为圆形按钮等等(这些类名都是由is-
开头赋给组件)。剩余3个函数cssVar…是给组件动态添加样式,element的button组件样式是由css变量设置的,打开控制台可以看到:root
下会有很多的—el-color
开头的颜色属性,组件会根据父组件传来的type属性值,用模板字符串拼接成css变量赋值给元素,这样元素就能拿到这样变量的具体颜色了。
巧妙地props定义
另外,button的props定义也很有意思。在button.ts
中,写了像Vue2的props选项的一个对象(在element中名为buttonPorps
),然后将这个对象传给defineProps
,这样,一个button
的props
就成功创建了。
当然不止这样,平时我写的props
定义顺序是先定义一个interface
,然后传给defineProps的泛型参数,但是将模块拆分之后,interface
也可能需要拆分,另起一个文件来管理,这时,由于Composition API
的文档说明,不能将外部引入的类作为泛型传给definePorps,会导致报错,在vue文件里extends
这个interface也会导致props没有值。
而element的做法是,用vue给的ExtractPropTypes
函数,将typeof buttonProps
作为这个函数的泛型参数,得到这个props的自定义类型,这个类型能给其他模块用(element里给了useButton
使用),非常巧妙。
总结
从源码可以看到,element的写法,根据不同的属性动态赋值,能够极大缩短代码长度,用一个模块实现多种不同的效果。