介绍computed的基本用法
基本用法 一
new Vue({
data () {
return {
num: 0
}
}
computed: {
result () {
return this.num++
}
}
})
基本用法 二 配合vuex使用
// vuex store.js
const store = new Vuex.Store({
state: {
storeNum: 2
}
})
// vue组件 xx.vue
<template>
<div>{{result}}</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
dataNum: 0
}
},
computed: mapState({
result: state => state.storeNum + this.dataNum
})
}
</script>
基本用法 三 配合 vuex使用, 及使用mapState, 还想写一些其他的属性
import { mapState } from 'vuex'
export default {
data () {
return {
num: 0
}
},
computed: {
...mapState({
storeNum: state => state.storeNum
}),
result() {
return this.num + 3 + this.storeNum
}
}
}
基本用法 四 修改 computed 属性值, 需要给computed计算属性添加setter
vue的计算属性基于
data
中的属性,要正确理解这句话,也就是说,可以在计算属性中使用data
中的属性值,如果计算属性使用了data
中的属性dataNum
,修改dataNum
的值,计算属性的值也会改变。不要直接修改计算属性, 直接修改计算属性视图不会改变。
export default {
data () {
return {
dataNum: 0
}
},
computed: {
result: {
get () {
return this.dataNum + 3
},
set (newValue) {
this.dataNum = newValue
}
}
}
}
Vue中如何初始化的computed, 使用computed属性时, vue都干了啥?
在初始化
computed
之前, Vue已经初始化完了props、methods、data
;所以在computed
中我们可以使用props、methods、data中的属性
,接下来我们看一下computed
的初始化过程。
// 源码位置 instance/ state.js
const computedWacthers = {lazy: true}
export function initState (vm) {
const opts = vm.$options
...
if (opts.computed) initComputed(vm, opts.computed) // 我们传入computed时 computed: {xxx: fn}
...
}
function initComputed (vm, computed) {
const watchers = vm._computedWatchers = object.create(null) // 后面用来存储计算属性中每个属性对应的watcher
for (const key in computed) {
// 遍历computed属性
const userDef = computed[key] // 获取computed中的每一项
const getter = typeof userDef === 'function' ? userDef : userDef.get
// 此处判断computed中的每一项是不是函数, 或者有没有get方法, 如果没有就抛错
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatchers
) // 为计算属性的每一项添加响应式
// 组件定义的计算属性已在组件原型上定义, 我们只需要在这里定义实例化时定义的计算属性。
definedComputed(vm, key, userDef)
}
}
function definedComputed (vm, key, userDef) {
// 不考虑服务端渲染
if (typeof userDef === 'function') {
sharedPropertyDefinition.get = createComputedGetter
sharedPropertyDefinition.set = noop
} else {
sharedPropertyDefinition.get = userDef.get ? createComputedGetter(key) : noop
sharedPropertyDefinition.set = userDef.set || noop
}
// 如果你设置了get, 没有设置set,然后你去修改计算属性,会报错。
Object.defineProperty(vm, key, sharedPropertyDefinition)
}
到这里我们已经了解
computed的初始化过程
,遍历computed
中的属性, 为每个属性设置对应的watcher实例
,然后为Vue实例化时的计算属性定义,木得了。完事儿。
使用computed计算属性时, vue都为我们做了什么?
在初始化
computed
时,为computed中的每个属性都设置了对应的watcher实例。当我们使用计算属性中的属性值时,我们就会调用computedGetter
方法, 这个方法上面没讲到,其实就是definedComputed
方法中的createComputedGetter
方法的返回值。接下来我们看一下当我们在使用计算属性中的值时,vue都为我们做了什么?
function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
// 在上面初始化computed时定义的_computedWatchers现在用上了
if (watcher) {
if (watcher.dirty) {
watcher.evaluate() // 这个方法其实就是调用watcher.get()获取值, 然后将 watcher.dirty = false, 将dirty设置为false
}
if (Dep.target) {
watcher.depend() // 搜嘎, 在这里, 他为每个key收集了依赖。
}
return watcher.value // 返回调用watcher.get()方法得到的value值, 其实就是调用的你计算属性中设置的函数。
}
}
}
看完上面的代码,我们清晰了,初始化时的new watcher 就埋下了伏笔, 后面当我们调用对应的计算属性时, 就会调用watcher的get方法, 然后将Dep.target赋值为当前watcher实例, 然后调用watcher.depend(), 为这个计算属性收集依赖。