多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# setup()、computed()和watch() ## 1. setup() `setup()`是在组件`created()`之前执行的,所以在`setup()`内部无法获取`this` - 参数一:props 组件接收的`props`数据可以在`setup()`函数内访问到 ``` export default { props: { title: String }, setup(props) { console.log(props.title) } } ``` 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) } ``` - 参数二:context: `context` 是一个上下文对象,可以通过 context 来访问 Vue 的实力 this。 `context` 内部包括三个属性:`attrs`、`slots`、`emit` ``` export default { setup(props, { attrs, slots, emit }) { // ... } } ``` 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 该计算属性为只读属性,不可写 ``` - computed()创建可读写计算属性 ``` // 注意使用的时候引入computed import { ref, computed} from 'vue' export default { name: 'Test', setup(){ // 定义一个响应式数据 const baby = ref('嘎嘎嘎') // 定义年龄 const age = ref(28) // computed计算属性传入一个回调函数 const areYouSureYouAreABaby = computed(() => { return `I'm sure,I'm a 300 month baby, ${baby.value}` }) // set和get方式 const setAge= computed({ get() { return age.value + 10 }, set(v) { age.value = v - 10 } }) // 对比vue2.0 /* computed: { areYouSureYouAreABaby (){ return `I'm sure,I'm a 300 month baby, ${baby.value}` }, setAge:{ get(){ return age + 10 }, set(v) { age = v - 10 } } } */ return { baby, age, areYouSureYouAreABaby } } } ``` ## 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] }) ``` watch 有三个参数:第一个是个getter(所谓getter写法就是你要写个getter函数),第二个是个回调函数,第三个是个options(这个参数是放vue2.0的deep或者immediate等可选项) ``` // 注意使用的时候引入watch import { ref, watch, watchEffect } from 'vue' export default { name: 'Test', setup(){ const baby = ref('嘎嘎嘎') const arr = ref(['翠花', '小红']) // 监听一个值的情况,有两种方式 // 第一种:直接放ref watch(baby, () => { return `I'm sure,I'm a 300 month baby, ${baby.value}` }) // 第二种:放ref的value值 watch(() => baby.value, () => { return `I'm sure,I'm a 300 month baby, ${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 } } } ``` - 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)  }   }, }); ``` 执行结果首先打印一次state和year值;然后每隔一秒,打印state和year值 watchEffect会自动收集依赖, 只要指定一个回调函数。在组件初始化时, 会先执行一次来收集依赖, 然后当收集到的依赖中数据发生变化时, 就会再次执行回调函数。 1. watchEffect 不需要手动传入依赖 2. watchEffect 会先执行一次用来自动收集依赖 3. 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触发的时候 } }) ```