笔者分析了自己的专栏数据,发现使用知识 专栏数据明显好于认知知识专栏,也就是说读者更感兴趣的是笔者的使用知识专栏,也就是具体的知识使用场景。笔者想这大概是因为这种文章能够直接或间接解决问题,能够有获得感。
笔者在《技术并一定不比其他高级》中写到技术实际是有重复单元的,而UI组件库正是功能单元的代表,所以笔者决定改变策略,先集中精力写好重复单元。
在教育学中,母题是各门学科包含若干知识点的基本题、典型题,也是中高考命题所参照的原型题。笔者把上述的重复单元也叫母场景。其他学科也可以如此分析。
因为实际开发中涉及element-ui比较多,优先从elment-ui组件开始分析并学习。element-ui版本:2.15.14。
首先笔者从所有组件中选出简单的20个组件,也是此次分析学习的对象。这些组件基本上没有引入其他依赖。
基本分析&模拟原生
原生html5标签是构建功能单元的基础,在没有Vue、React这类框架时,有jqueryUi、bootstrap等,这些为什么会存在?因为原生的标签离业务较远。
不管是jqueryUi、bootstrap封装的功能单元还是基于Vue、React封装的功能单元,一定不是完全符合业务要求的,但相对于原生html5标签来说,距离业务更近。
组件介绍
容器组件:container、main、aside、header和footer。快捷容器。
- button按钮组件和按钮组button-group:按钮是页面上允许点击的面积
- alert弹出组件:条形提示
- backtop回到顶部:当滚动过长方面回到顶部
- icon图标显示:图标快捷使用
- avatar头像组件:快捷头像
- badge标记组件:标记显示
- tag标签组件:标签显示
- progress进度条组件:进度条显示
- link链接文字:链接文字显示
- card卡片组件:卡片形式显示
- divider分割线组件:就是段落之间的分割线
- breadcrumb面包屑导航和breadcrumb-item面包屑导航内容:快捷面包屑导航
- page-header页头:快捷页头
本次分析学习的20个组件,相对来说都比较简单,传入对应的prop和绑定封装好的绑定方法就可以设置组件属性和处理组件方法。
至于封装了哪些属性,要结合组件的功能定位和业务定位。要逐渐记住每个组件对应的业务应用场景,这样才能理解为什么如此封装,才能更高效的使用。其他UI组件库也可以这样分析学习。
Vue组件的属性设置
都知道Vue组件可以通过prop输入参数,且所有参数都可以通过this.$props
获取到。另外,Vue组件上也可以直接写属性值,只不过这个时候不是通过prop获取,而是通过this.$attrs
js
<my-component custom-attr="hello" />
export default {
name: 'MyComponent',
created() {
console.log(this.$attrs['custom-attr']); // 输出:hello
}
}
而组件的class和style属性,Vue会将它们特殊处理,不包含在$attrs
中,而是分别提供$el.className
和$el.style
来访问,且需要在组件的mounted生命周期函数中才能获取到。
Vue组件的事件绑定
一般来说组件的事件绑定是通过this.$emit
触发的。对于v-model这种双向数据绑定,默认触发的是this.$emit('input')
。
Vue组件的ref设置
Vue组件ref设置,可以类比html5原生标签的类或者id,通过选择器选择到这个标签之后,就可以拿到标签的样式、className等属性和方法。
ref类似于此,可以拿到组件内部的属性和方法。这就是Vue组件对原生标签的模仿。
this.$options
还有在Vue组件中,this.$options包含了传递给Vue实例的所有选项。这包括了props、methods、data、computed等等。
学到知识点
判断slot里组件标签
slot在Vue中是插槽,可以通过this.$slots
获取到,默认是this.$slots.default
。看到UI组件源码中的container组件里面这行代码
js
computed: {
isVertical() {
if (this.direction === "vertical") {
return true;
} else if (this.direction === "horizontal") {
return false;
}
return this.$slots && this.$slots.default
? this.$slots.default.some((vnode) => {
// 注意这行注意这行注意这行注意这行注意这行
const tag = vnode.componentOptions && vnode.componentOptions.tag;
return tag === "unit-header" || tag === "unit-footer";
})
: false;
},
这个计算属性里面竟然可以通过vnode.componentOptions && vnode.componentOptions.tag
拿到slot内的组件的组件名,如果里面有 "unit-header" || tag === "unit-footer"
,就返回true
。真是学到了。
provide和inject
在button组件内部,有
js
inject: {
elForm: {
default: "",
},
elFormItem: {
default: "",
},
},
inject
是注入,这里面注入了elForm
和elFormItem
,然后在计算属性中使用
js
computed: {
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
buttonSize() {
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
},
buttonDisabled() {
// this.$options.propsData.hasOwnProperty("disabled")
return this.$options.propsData.hasOwnProperty("disabled")
? this.disabled
: (this.elForm || {}).disabled;
},
},
熟悉element-ui的应该可以看出来,这里就是可以通过给elment-ui的el-form
组件设置尺寸大小的方式设置el-form
内部组件的大小。
组件中使用render以及jsx语法
在Vue源码里,如果组件同时存在template和render,render的优先级是大于template的。
如果不想使用render的渲染函数方法h
,可以使用jsx语法,只不过这个时候需要下载相应的依赖支持。element-ui的avatar组件和tag组件,就使用了jsx。
具体开发中到底是采用template还是render写模板,要看组件的具体特点。
函数式组件slot和prop获取
在上面20个组件中,divider分割线组件是一个函数式组件,然后再函数式组件里面没有生命周期函数,没有this,有段代码
js
<div
v-if="slots().default && props.direction !== 'vertical'"
:class="['el-divider__text', `is-${props.contentPosition}`]"
>
<slot />
</div>
通过使用props
而不是this.$props
获取prop传入参数。还有slots().default
可以用$slots.default
替代。
代码地址
github:github.com/zhensg123/v...
(本文完)