时隔三月,继续开始学习了。

一、组件分类

大致分为三类组件

  • 页面组件
    • 由vue-router 产生的页面组件,承载当前页面的结构、数据、等业务,文件较大复杂,但一般较少的props和事件,因为作为路由的渲染,很少被复用,因此也很少提供对外的接口
    • 项目开发中,我们写的大部分代码都是这类的组件(页面)
    • 协同开发时,每人维护自己的页面,很少有交集
    • 这类组件相对是最好写的,主要是还原设计稿,完成需求,不需要太多模块和架构设计上的考虑
  • 通用组件
    • 不包含业务,独立、具体功能的基础组件,比如日期选择器模态框等。这类组件作为项目的基础控件,会被大量使用,因此组件的 API 进行过高强度的抽象
    • 独立组件的开发难度要高于第一类组件,因为它的侧重点是 API 的设计、兼容性、性能、以及复杂的功能
  • 业务组件
    • 在业务中被多个页面复用的,它与独立组件的区别是,业务组件只在当前项目中会用到,不具有通用性,而且会包含一些业务,比如数据请求
    • 而独立组件不含业务,在任何项目中都可以使用,功能单一,比如一个具有数据校验功能的输入框。

二、props、event、slot

一个再复杂的组件,都是由三部分组成的:prop、event、slot,它们构成了 Vue.js 组件的 API

Prop

prop 定义了这个组件有哪些可配置的属性,组件的核心功能也都是它来确定的。

写通用组件时,props 最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值

这点在组件开发中很重要,然而很多人却忽视,直接使用 props 的数组用法,这样的组件往往是不严谨的

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<button :class="'i-button-size' + size" :disabled="disabled"></button>
</template>
<script>
// 判断参数是否是其中之一
function oneOf (value, validList) {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true;
}
}
return false;
}

export default {
props: {
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default: 'default'
},
disabled: {
type: Boolean,
default: false
}
}
}
</script>

1
2
<i-button size="large"></i-button>
<i-button disabled></i-button>

定义了两个属性:尺寸 size 和 是否禁用 disabled

其中 size 使用 validator 进行了值的自定义验证,也就是说,从父级传入的 size,它的值必须是指定的 small、large、default 中的一个,默认值是 default,如果传入这三个以外的值,都会抛出一条警告。

组件里定义的 props,都是单向数据流,也就是只能通过父级修改,组件自己不能修改 props 的值,只能修改定义在 data 里的数据

使用组件时,也可以传入一些标准的 html 特性,比如 idclass

1
2
<i-button id="btn1" class="btn-submit"></i-button>

在组件内的 <button> 元素上会继承,并不需要在 props 里再定义一遍。这个特性是默认支持的,如果不期望开启,在组件选项里配置 inheritAttrs: false 就可以禁用了

slot

event

给组件 <i-button> 加一个点击事件,目前有两种写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<button @click="handleClick">
<slot></slot>
</button>
</template>
<script>
export default {
methods: {
handleClick (event) {
this.$emit('on-click', event);
}
}
}
</script>

1
2
<i-button @on-click="handleClick"></i-button>

上面的 click 事件,是在组件内部的 <button> 元素上声明的,这里还有另一种方法,直接在父级声明,但为了区分原生事件和自定义事件,要用到事件修饰符 .native,所以上面的示例也可以这样写:

1
<i-button @click.native="handleClick"></i-button>

如果不写 .native 修饰符,那上面的 @click 就是自定义事件 click,而非原生事件 click,但我们在组件内只触发了 on-click 事件,而不是 click,所以直接写 @click 会监听不到

通信

ref:给元素或组件注册引用信息;
$parent / $children:访问父 / 子实例。