0x00 简介
组件 Divider
多用于区隔内容。 本文将深入分析组件源码,剖析其实现原理,耐心读完,相信会对您有所帮助。packages/divider/src/main.vue
文件是组件源码实现。 🔗 组件文档 Divider 🔗 github源码 main.vue
更多组件分析详见 👉 📚 Element UI 源码剖析组件总览 。
本专栏的 gitbook
版本地址已经发布 anduril.gitbook.io/learning-el… ,内容同步更新中!
0x01 组件源码
组件divider/src/main.vue
SFC(单文件组件 single-file components ),声明了基于模板的函数式组件。
<template functional>
// ...
</template>
<script>
export default {
name: 'ElDivider',
props: {
// ...
}
};
</script>
attributes 属性
组件定义了2个prop : direction
、contentPosition
direction
设置分割线方向,默认值horizontal
,可选值为 horizontal / vertical
,定义了 validator
进行验证。如果传入其他值生成无效样式 el-divider--${direction}
。
direction: {
type: String,
default: 'horizontal',
validator(val) {
return ['horizontal', 'vertical'].indexOf(val) !== -1;
}
},
contentPosition
设置分割线文案的位置,默认值center
,可选值为 left / right / center
,定义了 validator
进行验证。如果传入其他值生成无效样式 is-${props.contentPosition}
。
contentPosition: {
type: String,
default: 'center',
validator(val) {
return ['left', 'center', 'right'].indexOf(val) !== -1;
}
}
template 模板内容
组件将创建一个 <div>
元素节点,用来绘制分割线。 该节点包含1个子节点 <div>
,内置了 slot
用于自定义分割线文案。 子节点只有组件是分割线水平方向,且提供插槽内容用于自定义分割线文案时才会渲染。
<div
v-bind="data.attrs"
v-on="listeners"
:class="[data.staticClass, 'el-divider', `el-divider--${props.direction}`]"
>
<div
v-if="slots().default && props.direction !== 'vertical'"
:class="['el-divider__text', `is-${props.contentPosition}`]"
>
<slot />
</div>
</div>
再进一步分析组件之前,先了深入了解下函数式组件。
函数式组件 context
函数式组件需要的一切都是通过 context
参数传递,组件中使用了该参数的部分属性:
props
:提供所有 prop 的对象slots
:一个函数,返回了包含所有插槽的对象data
:传递给组件的整个数据对象listeners
: 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是data.on
的一个别名。
其他属性 parent
、children
、scopedSlots
、injections
详见官方文档 。
context
接口定义 @2.6源码 types/options.d.ts#L136
export interface RenderContext<Props=DefaultProps> {
props: Props;
children: VNode[];
slots(): any;
data: VNodeData;
parent: Vue;
listeners: { [key: string]: Function | Function[] };
scopedSlots: { [key: string]: ScopedSlot };
injections: any
}
其中数据对象 data
类型为 VNodeData
官方文档 。
VNodeData
接口定义 @2.6源码 flow/vnode.js#L35 。
class Vs staticClass
从接口声明上看两者区别在于staticClass
只能是字符串。 class
支持所有其他格式,例如对象或数组。
declare interface VNodeData {
// ...
staticClass?: string;
class?: any;
// ...
};
下面使用 Vue.compile
实时编译模板字符串,对比区别,代码详见 模板编译。
指令 v-bind
用于 class
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
<div :class="['element','active']"></div>
编译(render)内容 输出 class
function anonymous(
) {
with(this){return _c('div',{class:['element','active']})}
}
不使用指令 v-bind
定义 class
字符串内容时。
<div class="active"></div>
编译(render)内容 输出 staticClass
function anonymous(
) {
with(this){return _c('div',{staticClass:"active"})}
}
组件功能
组件将创建一个 <div>
元素父节点,通过背景色绘制分割线。 el-divider
定义元素背景色, 通过el-divider--horizontal
或 el-divider--vertical
定义元素宽高实现水平、垂直分割效果
基于模板的函数式组件,可以通过 context
访问到其独立的上下文内容。 v-bind="data.attrs"
使用 data.attrs
传递任何 HTML attribute;v-on="listeners"
使用 listeners
(即 data.on
的别名) 传递任何事件监听器。
:class="[data.staticClass, 'el-divider', 'el-divider--${props.direction}']"
根据传入prop 值设置分割线方向样式,然后将静态class 和动态生成的class 合并 merge 。
组件包含1个子节点 <div>
,只有组件是分割线水平方向(props.direction !== 'vertical'
),且提供插槽内容(slots().default
)时才会渲染。根据contentPosition
生成文案位置样式, is-left
、 is-right
或is-center
。
0x02 组件样式
src/divider.scss
组件样式源码 packages\theme-chalk\src\divider.scss
使用混合指令 b
、 m
、e
、 when
嵌套生成组件样式。
// 生成 .el-divider
@include b(divider) {
// ...
// 生成 .el-divider--horizontal
@include m(horizontal) {
// ...
}
// 生成 .el-divider--vertical
@include m(vertical) {
// ...
}
// 生成 .el-divider__text
@include e(text) {
// ...
// 生成 .el-divider__text.is-left
@include when(left) {
// ...
}
// 生成 .el-divider__text.is-center
@include when(center) {
// ...
}
// 生成 .el-divider__text.is-right
@include when(right) {
// ...
}
}
}
lib/divider.scss
前文可知使用 gulpfile.js
编译 scss
文件转换为CSS
,经过浏览器兼容、格式压缩,最后生成 packages\theme-chalk\lib\divider.scss
,内容格式如下。
.el-divider {
// ...
}
.el-divider--horizontal {
// ...
}
.el-divider--vertical {
// ...
}
.el-divider__text {
// ...
}
.el-divider__text.is-left {
// ...
}
.el-divider__text.is-center {
// ...
}
.el-divider__text.is-right {
// ...
}
📚参考&关联阅读
"vm-attrs",vuejs.org
"vm-listeners",vuejs.org
"函数式组件",vuejs.org
“class vs staticclass”,stackoverflow
关注专栏
如果本文对您有所帮助请关注➕、 点赞👍、 收藏⭐!您的认可就是对我的最大支持!
此文章已收录到专栏中 👇,可以直接关注。