Vue3-02-setup()/computed()/watch()
fuzuxian 7/10/2021 Vue3
# 1. setup()
setup()
是在组件created()
之前执行的,所以在setup()
内部无法获取this
- 参数一:props
组件接收的props
数据可以在setup()
函数内访问到
export default {
props: { title: String },
setup(props) { console.log(props.title) }
}
1
2
3
4
2
3
4
props 具有响应性,不能使用 ES6 解构它,这会使其失去响应性。如果需要解构,可以使用 toRefs()
const { title } = toRefs(props)
console.log(title.value)
// 如果 title 是一个可选的属性,需使用 toRef()
import { toRef } from 'vue'
setup(props) {
const title = toRef(props, 'title')
console.log(title.value)
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 参数二:context:
context
是一个上下文对象,可以通过 context 来访问 Vue 的实力 this。
context
内部包括三个属性:attrs
、slots
、emit
export default {
setup(props, { attrs, slots, emit }) { ... }
}
1
2
3
2
3
context 是一个常规的 js 对象,它不具有响应性可以直接对它解构。
但 attrs 和 slots 是有状态的对象,当组件本身更新时它们也会随之更新,避免解构
# 2. computed()
- computed()创建只读计算属性
const count = ref(1)
// 创建一个只读性计算属性,依赖于count值
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // error 该计算属性为只读属性,不可写
1
2
3
4
5
2
3
4
5
- computed()创建可读写计算属性
// 注意使用的时候引入computed
import { ref, computed} from 'vue'
export default {
name: 'Test',
setup(){
const baby = ref('嘎嘎嘎') // 定义一个响应式数据
const age = ref(28)
// computed传入回调函数
const areYouSureYouAreABaby = computed(() => {return `${baby.value}`})
// set和get方式
const setAge= computed({
get() { return age.value + 10 },
set(v) { age.value = v - 10 }
})
// 对比vue2.0
/*
computed: {
areYouSureYouAreABaby (){ return `${baby.value}` },
setAge:{
get(){ return age + 10 },
set(v) { age = v - 10 }
}
}
*/
return { baby, age, areYouSureYouAreABaby }
}
}
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
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
# 3. watch()
watch()监听多个数据源,第一个参数中,要监听的数据源以数组的形式传入。
import { ref, watch } from 'vue'
const count = ref(0)
const count2 = ref(1)
watch([count,count2],([newCount,newCount2],[oldCount,oldCount2])=>{})
//还有第二种写法
watch([count, count2], (newValue, oldVlaue) => {
console.log(newValue) //[newCount, newCount2]
console.log(oldValue) //[oldCount, oldCount2]
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
watch 有三个参数:第一个是个getter(所谓getter写法就是你要写个getter函数, 第二个是个回调函数,第三个是个options(这个参数是放vue2.0的deep或者immediate等可选项)
import { ref, watch, watchEffect } from 'vue' // 使用需要引入watch
export default {
name: 'Test',
setup(){
const baby = ref('嘎嘎嘎')
const arr = ref(['翠花', '小红'])
// 监听一个值的情况,有两种方式 |||| 第一种:直接放ref
watch(baby, () => `${baby.value}`)
// 第二种:放ref的value值
watch(() => baby.value, () => `${baby.value}`)
// 监听多个值的时候 ,第一个参数是个数组,里面放监听的元素
watch([baby, arr], (v, o) => {
// 这里的v,o也是数组,所以你取值的时候v[0],v[1]拿到第几个元素的变化
...
}, { deep: true, immediate: true })
// 或者写成
watch([baby,arr], ([baby, arr], [prebaby,prearr]) => { ... })
// 对比vue2.0
/*
watch: {
baby(v, o) {},
arr: {
handle(v,o) {},
deep: true,
immediate: true,
flush: 'pre' // 这个默认有三个参数,'pre'| 'post' | 'sync',默认‘pre’组件更新前运行,'post'组件渲染完毕后执行,一般用于你需要去访问$ref的时候可以用这个,'sync'是一旦你的值改变你需要同步执行回调的时候用这个
}
}
*/
return {baby,areYouSureYouAreABaby,data }
}
}
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
31
32
33
34
35
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
31
32
33
34
35
# vue3.0 watchEffect 用法
import { defineComponent, ref, reactive, toRefs, watchEffect } from"vue";
exportdefault defineComponent({
setup() {
const state = reactive({nickname: "xiaofan", age: 20});
let year = ref(0)
setInterval(() =>{ state.age++; year.value++ },1000)
watchEffect(() => { console.log(state); console.log(year); });
return { ...toRefs(state) }
},
});
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
执行结果首先打印一次state和year值;然后每隔一秒,打印state和year值
watchEffect会自动收集依赖, 只要指定一个回调函数。在组件初始化时,会先执行一次来收集依赖,然后当收集到的依赖中数据发生变化时,就会再次执行回调函数。
- watchEffect 不需要手动传入依赖
- watchEffect 会先执行一次用来自动收集依赖
- watchEffect 无法获取到变化前的值, 只能获取变化后的值
// watchEffect 有两个参数,一个是副作用函数(就是外部的数据对这个函数产生影响的,通俗点说就是在这个函数内部使用了外面的变量等),一个是options()
// 在vue2.0中,我们一般在created里添加一些监听事件,比如你的$bus的一些事件监听,在setup中就可以在这个里面写
watchEffect((onInvalidate) => {
// 这里的变化就相当于依赖了age.value,如果age变化了就会触发这个监听
// 刚刚创建组件的时候会立即执行这个
const _age= `her age is ${age.value}`
console.log(_age)
//有时候你需要在这里挂载一些监听事件
const handerClick = ()=>{}
document.addEventlistener('click', handerClick)
// 在vue2.0我们需要在destroy的时候remove它,这里提供了一个方法onInvalidate回调解决remove的问题
onInvalidate(()=>{
/*
执行时机: 在副作用即将重新执行时,就是在每次执行这个watchEffect回调的时候会先执行这个,
如果在setup()或生命周期钩子函数中使用watchEffect, 则在卸载组件时执行此函数。
*/
document.removeEventListener('click',handerClick )
})
})
// 这个也是支持async,await的
const data = ref(null)
watchEffect(async onInvalidate => {
// 假设个接口获取数据的
data.value = await fetchData()
onInvalidate(() => {...})
})
// 再来理解options:这里有三个参数flush,onTrigger,onTrack
watchEffect(onInvalidate => { onInvalidate(() => {...})}, {
flush: 'pre', // 跟watch一样,默认pre,组件更新前去调用
onTrigger(e) {}, // 依赖项变化时候触发这个即依赖项的set触发的时候
onTrack(e) {} // 依赖项被调用的时候触发这个即依赖项的get触发的时候
})
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
31
32
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
31
32