vue3(六)computed、watch、watchEffect

407 阅读2分钟

computed 计算属性

计算属性是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值没变化的时候,使用的是缓存中的属性值。

基本用法

函数形式 (只能读取值)

<template>
  name:{{ name }}
  <hr>
  newName:{{ newName }}
</template>

<script setup lang='ts'>
import { ref, computed } from 'vue'

const name = ref('小刘')

const newName = computed<string>(() => {
  return "我不是" + name.value
})

</script>

对象形式 (可以修改值)

<template>
  name:{{ name }}
  <hr>
  newName:{{ newName }}
  <div>
    <button @click="edit">修改</button>
  </div>
</template>

<script setup lang='ts'>
import { ref, computed } from 'vue'

const name = ref('小刘')

const newName = computed({
  get: () => {
    return name.value
  },
  set: (value) => {
    name.value = value
    console.log("修改了", value);
  }
})
const edit = () => {
  newName.value = "修改" + newName.value
}
</script>

watch 侦听器

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。 watch() 接收三个参数
第一个是需要侦听的数据源
第二个是数据源变化的时候执行的callback
第三个是一个对象,是可选的,配置项有

immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined。  
deep:开启深度监听,reactive 创建的响应式数据自动开启。
flush:调整回调函数的更新时机,pre:组件更新前,sync:同步执行,post:组件更新后  
onTrack / onTrigger:调试侦听器的依赖

基本用法

<template>
  name: <input v-model="name" />
</template>

<script setup lang='ts'>
import { ref, watch } from 'vue'

const name = ref('小刘')

watch(name, (newval, oldval) => {
  console.log("newval:", newval);
  console.log("oldval:", oldval);
})
</script>

监听多个数据源时,使用数组的方式传入,也是通过数组得到新旧value

const name = ref('小刘')
const name2 = ref('小刘22')

watch([name, name2], ([newval1, oldval1], [newval2, oldval2]) => {
  console.log("newval1:", newval1);
  console.log("oldval1:", oldval1);

  console.log("newval2", newval2);
  console.log("oldval2:", oldval2);
})

当一个对象里面有多个属性,只想监听其中一个的话,可以使用函数返回的形式传入要监听的数据源

例如有 name 和 age,我只想监听 name

const person = reactive({
  foo: {
    bar: {
      name: "小刘",
      age: 20
    }
  }
})
watch(() => person.foo.bar.name, (newval, oldVal) => {
  console.log('newval:', newval)
  console.log('oldVal:', oldVal)
})

第三个参数示例

如果要监听这种深层次对象的话,我们需要开启 deep 深度监听 (通过 reactive 实现的响应式数据会默认开启)

这样写的时候,修改 name 值不会触发监听

<template>
  name: <input v-model="person.foo.bar.name" />
</template>

<script setup lang='ts'>
import { ref, watch } from 'vue'

const person = ref({
  foo: {
    bar: {
      name: "小刘"
    }
  }
})
watch(person, (newval, oldVal) => {
  console.log('newval:', newval)
  console.log('oldVal:', oldVal)
})
</script>

使用 deep 深度监听,就可以监听到变化了。

watch(person, (newval, oldVal) => {
  console.log('newval:', newval)
  console.log('oldVal:', oldVal)
}, {
  deep: true // 开启深度监听
})

watchEffect 高级侦听器

非惰性的,会立即运行一次函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
watchEffect 接收两个参数,第一个要执行的函数(自动侦听函数内用的响应式数据),第二个是配置项

使用示例

<template>
  num: <input v-model="num" />
</template>

<script setup lang='ts'>
import { ref, watchEffect } from 'vue'

const num = ref(1)

watchEffect(() => {
  console.log(num.value);
})
</script>

配置项

flush:调整回调函数的更新时机,pre:组件更新前,sync:同步执行
onTrack(): 开发环境中方便调试,立即执行
onTrigger(): 开发环境中方便调试,更新时执行
watchEffect(() => {}, {
  flush: 'post', 
  onTrack(e) { 
    debugger
  },
  onTrigger(e) { 
    debugger
  }
})

副作用清除

watchEffect 函数里有一个参数 oninvalidate,在数据变化时,会在函数内先执行

const num = ref(1)
watchEffect((oninvalidate) => {
  oninvalidate(() => {
    console.log("before");
  })
  console.log(num);
})

停止跟踪,watchEffect 返回一个函数,调用之后将停止监听

<template>
  num: <input v-model="num" />
  <button @click="stop">停止监听</button>
</template>

<script setup lang='ts'>
import { ref, watchEffect } from 'vue'

const num = ref(1)
const stop = watchEffect((oninvalidate) => {
  oninvalidate(() => {
    console.log("before");
  })
  console.log(num);
})
</script>