萝三画室

详解vue-从熟悉到熟练-part2-对象的选项们

前文我们知道,在vue单文件组件中,最终会导出一个对象。

1
2
3
<script>
export default {};
</script>

vue已经为我们预先指定好了这个对象一些选项,如data, components, methods, computed, watch, mixins, filters, 钩子函数等等。本文我们将从组件的使用场景出发,详解这些属性和方法的用法。

组件内部属性

这里的内部指的是,组件自用的,不与外部产生交互的属性。如果我们想构造出一个不与外部交互的静态页面,那么只使用这里的选项就可以了。

data用于保存组件内部状态

对于一个组件,它独有的内部状态全部保存在data中。组件被创建后,你可以在任何地方更改data中的状态。与状态绑定的一切都会跟随状态的变化响应式地变化:绑定的DOM会重新渲染,绑定的计算属性(computed)会自动更新,对应的观察者(watch)会自动执行。

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
<template>
<button @click="changeMsg">
{{msg}}
</button>
</template>
<script>
export default {
data() {
return {
msg: 'hello',
};
},
methods: {
changeMsg() {
this.msg = 'world';
},
},
};
</script>
```
以上栗子,页面初始状态button上显示的文字是'hello',点击按钮后,文字会变为'world'。
## methods用于定义方法
可以回头看上个栗子,我们用到了methods这个属性。它是个对象,其中定义了组件需要的方法。changeMsg这个函数就是用来改变组件内部状态的方法。
## computed用于定义"随着状态改变而改变的状态"
在实际应用中,我们通常会将data用于保存***基本状态***。在很多场景下,我们需要***对基本状态做一些转换***再使用。直接将转换逻辑写到用处,或者多处都用到同一逻辑时,我们就发现代码不很整洁,并且将逻辑散落到各处。


1
2
computed计算属性就是帮我们处理这个问题的。一个计算属性就是一个基于一个或几个基本状态的,不带参数的,有返回值的函数。


1
2
3
上栗中,我们将散落在```<template>```中的状态转换逻辑写到计算属性reversedMsg中,这样便于逻辑的统一管理,也便于复用。计算属性会随着它内部引用的状态变化而变化,也就是说,只要msg变化,reversedMsg就会立即执行,返回一个新值。同data中的状态一样,与计算属性绑定的一切都会跟随着它的变化响应式地更新。
计算属性默认只有getter,在需要时也可以围棋设置一个setter。使用setter的一个常用场景是:使用v-model双向绑定vuex中的state时。


1
2
3
## watch用于侦听变化,在变化之后do something
watch和computed有一些相似,它们都是在变化后自动执行的函数
主要区别在于:computed无参有返回值,是一个‘随基本状态变化而变化的状态’;watch接受两个参数,不需要返回值,是‘在状态变化之后,做些什么’。此外还有性能上的区别,请查看官方文档。


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
用法就是这样,至于什么时候用computed什么时候用watch,就看需要的是状态还是做一些事就可以了。
## 钩子函数
钩子函数就是在一个vue组件的完整生命周期中的某些阶段,我们可以做些什么。与react不同,vue的钩子函数比较多,并且不带参,相当于将react的钩子按照before和after进一步细分。
1. beforeCreate:
vue组件开始创建前,此时组件内所有都是不可用的,可以用来做一些组件创建前的准备工作。
2. created:
vue组件创建完成,此时虚拟DOM已准备好,组件内状态,方法等全部可用,但并未生成真实DOM,不能直接操作DOM或使用ref等方法简介使用DOM,可以用来发送请求以及做一些初始化工作。
3. beforeMounted:
虚拟DOM挂载到真实DOM之前。由于它与created相似,因此通常用得比较少。
4. mounted:
虚拟DOM已挂载到真实DOM元素上,vue的所有方法都可用,这个钩子中适合做一些依赖于DOM元素的操作。
5. beforeupdate:
状态改变之前,适合基于变化的判断和拦截。在跨组件使用时,相当于对另一个组件的watch。
6. updated:
状态改变之后。
7. beforeDestroy:
组件销毁之前,组件内部所有都存在且可用(类似mounted),适合于做一些销毁工作。
8. destroyed:
组件销毁之后,组件内所有都消失且不可用(类似beforeCreate)。
#与其他组件交互的属性
根据上一节的属性,我们可以构建起一个独立的,不与外部交互的静态页面。然而组件之间一定会存在通信的场景,这就需要我们对各自独立的组件之间建立连接。
## 引入其他单文件组件时,用components局部注册
当我们的组件需要引入其他组件时,引入后需要在components中注册, 然后才可以在```<template>```中以tag时形式写入。


1
2
3
## 用props声明对外的数据接口
使用components只是让其他组件在本组件内可用。为了完成组件之间的通信,我们还需要建立连接。在vue的概念中,组件之间是通过数据和事件完成通信的。父组件将数据通过子组件定义的props传递到子组件;子组件通过提交(emit),并在父组件中监听(on)来传递事件。(vue组件之间的通信方法不止这一种,后续会单独详述)
子组件a.vue:


1
父组件:


1
最终渲染出来的元素将会是


hello world

1
2
3
4
5
props属性可以是数组也可以是对象,还支持类型验证,详情请查官方文档。
# 复用和继承
## filters定义过滤器
一个过滤器就是一个管道,是一个带参数,有返回值的纯函数,常在```<template>```中用于一些常见的文本格式化。


1
2
3
4
5
6
7
8
9
上栗中,过滤器parseTime的作用就是将时间戳转换为指定格式的时间,它在 ```<template>```中的用法就像管道:```<div>{{ timeStamp | parseTime }}</div>```。
```|```左侧是待转换的时间戳,右侧是过滤器,表达式结果就是过滤器返回的结果。
由于过滤器实际上就是一个纯函数,所以当然我们也可以在```<script>```中当做普通函数使用。
## mixins用于混入公用属性
组件的作用域是独立的,当多个组件共用一个方法时,我们一般会把方法抽到utils,按需引用。然而对于vue,我们还可以抽出其他属性。在vue中,我们可以把所有的属性都提出来放入一个JS文件中,再通过mixin混入。混入的属性将会与组件内部的属性merge到一起,变为组件的属性。

//logTimeInterval.js
import moment from ‘moment’;
import { LOG_INTERVAL } from ‘@/constants/application’;

export default {
data() {
return {
LOG_INTERVAL,
interval: LOG_INTERVAL.ONEWEEK.type,
};
},
computed: {
targetTimeInterval() {
const { time, unit } = LOG_INTERVAL[this.interval];
return {
from: moment().subtract(time, unit).valueOf(),
to: moment().valueOf(),
};
},
},
};

//组件

import logTimeInterval from ‘./logTimeInterval.js’;

export default {
mixins: [logTimeInterval],
data() {
return {
content: ‘timeInterval:’,
};
},
};

1
2
## extends继承其他组件的属性
extends的作用同mixins相同,都是将组件外部的属性merge为自身属性。区别在于minxin是混入一个js文件中的公共属性;extendes是基于一个vue组件,相当于继承一个组件。可以理解为:mixins是抽属性,extends是抽组件extends的使用场景更像是面向对象的抽父类。

//logTimeInterval.vue


//组件

import logTimeInterval from ‘./logTimeInterval.vue’;

export default {
extends: logTimeInterval,
data() {
return {
content: ‘timeInterval:’,
};
},
}
```