今天我们盘点一下Vue3.x的计算属性和监听computed-watch

1,479 阅读3分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。

setup(props,context)中的参数

  • setup执行时机,在beforeCreate()生命周期函数之前,并且this===undefined
  • props接收父组件传递数据
    如果父组件传递数据,子组件不定义props接收,则回报警告,反之,子组件定义props,父组件不传递,则子组件值为undefined;
    子组件接收的值,则被加工成代理对象,即是响应式数据。
  • context事件参数(上下文对象)
    attrs:当父级传递数据,存放props中未声明接收的变量,相当于Vue2.x中的attrs; emit:事件传递,相当于Vue2.x中的attrs;\ emit:事件传递,相当于Vue2.x中的.emit(),不同之处在Vue3.x中需要emits:['事件名'] ,声明一下,和props声明变量功能类似,当然不声明也不影响使用,就是会出现警告!
    slot:不陌生,就是插槽,存在一些小差异:
// 写法一:
 <Demo>
        <span>父级内容</span>
</Demo>
// 写法二:
 <Demo>
    <template slot="header">
        <span>父级内容</span>
    </template>
</Demo>

以上写法,context.slot都是默认插槽,看不到插槽名称为header的内容,与Vue2.x不同之处,或者说一些框架向下兼容问题。

 <Demo>
    <template v-slot:header>
        <span>父级内容</span>
    </template>
</Demo>

通过v-slot:header写法,则正常,推荐该写法。

计算属性computed

  • Vue2.x中写法
computed: {
    demo(){
        return this.xxx*100
    }
}
  • 搬到Vue3.x也可以使用,但是不建议这样混合使用
    在Vue3.x中,通过import {reactive,computed} from 'vue',接下来:
setup(){
    let p = reactive({
        xxx: 10
    })
    // computed默认写法
    p.demo = computed(()=>{
         return p.xxx*100
    })
    return {
        p
    }
}
  • 在这里对computed扩展一下(完整写法),和Vue2.x其实一样的
p.demo = computed({
    get(){
        return p.xxx*100
    },
    当计算组合值被修改,则通过代理对象修改源数据
    set(value){
           // value接收修改的值,在这里可以干点啥
           p.xxx = value/100
    }
})

watch监听:watch(监听对象或者函数,fn,option)

  • Vue3.x的监听属性用法有些不同,在使用之前肯定先引入import { watch,ref,reactive } from 'vue'
setup(){
        let sum = ref(100) // 基本类型
        watch(sum,(newVal,oldVal)=>{
            console.log(newVal,oldVal))
        },{
        // 第三个参数,配置项
          //  immediate: true,
           //  deep: true // 其实被强制开启,改成false也无效,下面会有两种情况可以起作用
        })
        return { sum  }
}
  • 可以写多个watch(sum1,()=>{}),但是Vue3.x提供数组写法
watch([sum,sum1],(newVal,oldVal)=>{ 
    //newVal,oldVal 也是数组,值对应前面箭筒数组的值 
})

通过reactive定义,存在坑,oldVal对象中的count是不正确的,目前无法解决
通过let p = ref({});watch(p.value,(n,o)=>{}),也是不能解决,要清楚ref()中传入一个对象,最后还是走reactive的,所以根源就在于reactive的实现上。
注:1、实在需要count的新旧数据,可以单独出来当做一个基本类型定义即可;
2、也可以通过函数的方式watch(()=>p.count,()=>{})的形式即可。

setup(){
        let sum = reactive({
            count: 100
        }) // 基本类型
        watch(sum,(newVal,oldVal)=>{
            console.log(newVal,oldVal))  // newVal,oldVal这两对象中的count是相等的,目前无法解决
        })
        return { sum }
}

下面正式进入监听的一些实现方式

  • 监听对象某一个属性,可以如下:
let p = reactive({count: 200})
watch(()=>p.count,(nVal,oVal)=>{
    // 干点啥
})
  • 监听对象多个个属性,可以如下:
let p = reactive({count: 200,total: 5000})
watch([()=>p.count,()=>p.total],(nVal,oVal)=>{
    // 干点啥
})
  • 监听相应数据对象中的对象,deep:true就起作用了,可以如下:
let p = reactive({
    count: 200,
    type:{ name: '张三' }
})
watch(()=>p.type,(nVal,oVal)=>{
    // 干点啥
},{deep: true})
  • 通过ref定义引用类型注意问题
    通过ref定义引用类型,注意监听的是需要响应式对象数据的存放的容器,故兼容p.value或通过deep:true开启深度监听。
let p = ref({name: '张三',age: 18,job:{//...}})
console.log(p)
watch(p.vaule,(nVal,oVal)=>{})
watch(p,()=>{},{deep: true})


watch基本应该整理完成了。