详解Vue中Computed与watch的用法与区别

目录
  • computed
    • computed只接收一个getter函数
    • computed同时接收getter函数对象和setter函数对象
    • 调试 Computed
  • watchEffect
    • 立即执行 监听基本数据类型
    • 停止watchEffect
    • 清理watchEffect
    • watchPostEffect 和 watchSyncEffect
    • watchEffect不能监听对象
  • watch
    • 监听单个数据
    • 监听多个数据(传入数组)
  • 官方文档总结
    • computed
    • watchEffect
    • watch

computed

computed只接收一个getter函数

1、getter必须有返回值

2、computed返回一个只读响应式ref对象 (只读、响应式、对象)

注意:omputed只接收一个getter函数时,返回的只读对象,也就是不能修改他的返回值!

getter触发条件

  • 1、computed返回值首次被读取时
  • 2、getter绑定的响应式变量被修改时
<script setup>
import { ref,computed } from 'vue'
const num = ref(1)
//computed返回一个只读响应式ref对象computedNum
//computedNum是只读属性
let computedNum = computed(() => num.value + 1)
</script>
​
<template>
    <p> num:{{ num }} </p>
    <p>computedNum:{{ computedNum }}</p>
    <!-- 修改响应式变量num 触发与之绑定的computed的getter-->
    <button @click="num++">num++</button>
    <!-- computedNum是只读属性-->
    <button @click="computedNum++">computedNum++</button>
</template>

computed同时接收getter函数对象和setter函数对象

1、setter函数对象没有返回值

2、computed返回一个可读可写响应式对象

3、setter函数对象有参数,是getter的返回值,也是computed的值

4、修改computed返回值,触发setter函数对象执行,但不会真正修改computed返回值(setter内改变getter计算值就会改变computed返回值)

setter触发条件

computed返回值被修改时

实例:

<script setup>
import { ref, computed } from 'vue'
const num = ref(1)
//getter(只读)
let computedNum = computed(() => num.value + 1)
//getter和setter (可读可写)
let computedNum2 = computed({
    get: () => num.value + 1,
    set: (val) => {
         console.log(val);
        //setter中修改ref响应式变量num,将触发关联的num的getter计算
        //computedNum和computedNum2的getter同时触发
         num.value++
          }
})
</script>
​
<template>
    <p> num:{{ num }} </p>
    <p>computedNum:{{ computedNum }}</p>
    <p>computedNum2:{{ computedNum2 }}</p>
    <button @click="num++">num++</button>
    <!-- computedNum是只读属性,会有警告提醒 Write operation failed: computed value is readonly-->
    <button @click="computedNum++">computedNum++</button>
     <!-- computedNum2是可读可写属性-->
    <button @click="computedNum2++">computedNum2++</button>
</template>

调试 Computed

使用范围:仅开发模式生效

computed的第二参数:带有 onTrackonTrigger 选项的对象

  • onTrack :getter关联的响应式数据时触发。
  • onTrigger :getter关联的响应式数据被修改时触发
<script setup>
import { ref, computed } from 'vue'
const num = ref(1)
let computedNum = computed(() => num.value + 1, {
    onTrack: (e) => {
        console.log('onTrack');
        console.log(e);
    },
    onTrigger: (e) => {
        console.log('onTrigger');
        console.log(e);
    }
})
​
</script>
​
<template>
    <p> num:{{ num }} </p>
    <p>computedNum:{{ computedNum }}</p>
    <!--每次 num++将触发onTrigger -->
    <button @click="num++">num++</button>
</template>

watchEffect

语法:

  • 参数1:触发监听回调函数,回调函数可传入一个onInvalidate函数作为参数!
  • 可选参数2:对象,包含3个可选属性flush、onTrack、onTrigger

立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

1、会立即执行一次(和watch的immediate属性效果一致)

2、关联的响应式数据被修改时触发

3、会自动感知代码依赖,和watch不一样,watchEffect会主动绑定监听数据

局限性:不能监听对象(但可以监听对象的属性),只能监听类似ref基本数据类型的响应式数据

立即执行 监听基本数据类型

<script setup>
import { ref, watchEffect } from 'vue'
const num = ref(1)
//会立即执行一次
watchEffect(() => {
    console.log('watchEffect');
    num.value++
})
</script>
​
<template>
    <p>num: {{ num }}</p>
    <button @click="num++">num++</button>
</template>

停止watchEffect

隐式:组件卸载时自动停止

显式:调用watchEffect 返回值

const stop = watchEffect(() => {
  /* ... */
})
​
// 显式停止
stop()

清理watchEffect

语法: watchEffect( onInvalidate=>{ onInvalidate(()=>{ }) })

onInvalidate 是一个函数!优先触发!

onInvalidate 执行时机:

1、watchEffect被重新触发时

2、组件卸载时

注意:关联的响应式数据首次被修改时不会触发onInvalidate函数!

作用: 清理定时器、事件监听removeEventListener 。。。

import { ref, watchEffect } from 'vue'
const num = ref(1)
watchEffect((onInvalidate ) => {
    console.log('watchEffect-1');
    num.value++
    onInvalidate (()=>{
        console.log('onInvalidate-2');
    })
    console.log('watchEffect-3');
})
​
//1、watchEffect   被重新触发时
// onInvalidate-2
// watchEffect-1
// watchEffect-3
//2、组件卸载时
// onInvalidate-2
//3、关联的响应式数据首次被修改(组件被挂载时)
//  watchEffect-1
//  watchEffect-3

watchPostEffect 和 watchSyncEffect

watchPostEffectwatchSyncEffect在Vue3.2新增,是watchEffect类似语法糖的东西,

watchEffect可选参数对象{ flush?: 'pre' | 'post' | 'sync'}中post和sync的语法糖,pre是默认值

推迟触发watchPostEffect

watchPostEffect 是watchEffect可选参数对象{flush:'post'}的语法糖

推迟watchEffect触发时机!组件更新前触发!也就是在生命周期onBeforeUpdateonUpdated之间触发

语法:

//推迟触发watchEffect
watchEffect(
  () => {
    /* ... */
  },
  {
    flush: 'post'
  }
)
//Vue3.2语法糖watchPostEffect
watchPostEffect(()=>{
  /* ... */
})

实例:

//实验watchEffect第二参数 flush: 'post'属性
watchEffect(() => {
    console.log("实验watchEffect第二参数 {flush: 'post'}属性");
    console.log(obj.age);
},{
   flush:'post'
})
watchEffect(() => {
    console.log("watchEffect正常时机触发");
    console.log(obj.age);
})
//生命周期onUpdated
onUpdated(()=>{
    console.log('onUpdated()');
})
//生命周期onBeforeUpdate
onBeforeUpdate(()=>{
    console.log('onBeforeUpdate()');
})

修改obj.age时,执行结果:

watchEffect正常时机触发
onBeforeUpdate()
实验watchEffect第二参数 {flush: 'post'}属性
onUpdated()

同步触发watchSyncEffect

watchSyncEffect 是watchEffect可选参数对象{flush:'sync'}的语法糖

强制效果始终同步触发!效率低!也就是默认watchEffect之前触发

语法:

watchEffect(
  () => {
    /* ... */
},
  {
    flush: 'sync'
  }
)
//Vue3.2语法糖watchSyncEffect
watchSyncEffect(()=>{
  /* ... */
})

watchEffect不能监听对象

//假设修改了对象的属性值-修改了obj.age
const obj = reactive({ name: '小明', age: 18 })
//watchEffect不能监听对象变化
watchEffect(() => {
    console.log('watchEffect监听对象变化');
    console.log(obj);
})
//watchEffect可以监听对象属性变化
watchEffect(() => {
    console.log('watchEffect监听对象属性变化');
    console.log(obj.age);
})
//watch监听对象变化
watch(obj, (obj) => {
    console.log('watch监听对象变化');
    console.log(obj);
})

总结:watchEffect用来监听能监听基本数据类型,不能监听对象,但能监听对象的属性;watch能监听基本数据类型和对象!

watch

语法:

  • 参数1-被监听数据(形式:单个数据、数组、带返回值的回调函数)
  • 参数2-触发监听的回调函数,无返回值
  • 可选参数3-对象{immediate: true,deep:true},对象含2个可选参数和Vue2参数效果一致

Vue3的watch和Vue2的watch是基本一样的

1、需要指定监听数据

2、惰性,只在被监听数据变化时才触发(immediate属性可以设置在初始化的时候触发)

监听单个数据

参数1被监听数据的形式:

1、单个基本数据类型;

2、回调函数:返回值为单个基本数据类型;

// 侦听一个 getter
//被监听数据传入一个带返回值的回调函数
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)
​
// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

监听多个数据(传入数组)

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

官方文档总结

以下代码截取官方文档,从TS代码可以看出很多关于watch和watchEffect函数参数和返回值的细节!

computed

computed只接收一个getter函数

getter触发条件:

1、computed返回值首次被读取时

2、getter绑定的响应式变量被修改时

computed同时接收getter函数对象和setter函数对象

setter触发条件:computed返回值被修改时

// 只读的
function computed<T>(
  getter: () => T,
  debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>
​
// 可写的
function computed<T>(
  options: {
    get: () => T
    set: (value: T) => void
  },
  debuggerOptions?: DebuggerOptions
): Ref<T>
interface DebuggerOptions {
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}
interface DebuggerEvent {
  effect: ReactiveEffect
  target: any
  type: OperationTypes
  key: string | symbol | undefined
}

watchEffect

  • 参数1-触发监听回调函数,回调函数可传入一个onInvalidate函数作为参数!
  • 可选参数2-对象,包含3个可选属性flush、onTrack、onTrigger
function watchEffect(
  effect: (onInvalidate: InvalidateCbRegistrator) => void,
  options?: WatchEffectOptions
): StopHandle
​
interface WatchEffectOptions {
  flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}
​
interface DebuggerEvent {
  effect: ReactiveEffect
  target: any
  type: OperationTypes
  key: string | symbol | undefined
}
​
type InvalidateCbRegistrator = (invalidate: () => void) => void
​
type StopHandle = () => void

watch

  • 参数1-被监听数据(形式:单个数据、数组、带返回值的回调函数)
  • 参数2-触发监听的回调函数,无返回值
  • 参数3-传入{immediate: true,deep:true}对象和Vue2参数效果一致
// 侦听单一源
function watch<T>(
  source: WatcherSource<T>,
  callback: (
    value: T,
    oldValue: T,
    onInvalidate: InvalidateCbRegistrator
  ) => void,
  options?: WatchOptions
): StopHandle
​
// 侦听多个源
function watch<T extends WatcherSource<unknown>[]>(
  sources: T
  callback: (
    values: MapSources<T>,
    oldValues: MapSources<T>,
    onInvalidate: InvalidateCbRegistrator
  ) => void,
  options? : WatchOptions
): StopHandle
​
type WatcherSource<T> = Ref<T> | (() => T)
​
type MapSources<T> = {
  [K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never
}
​
// 参见 `watchEffect` 共享选项的类型声明
interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean // 默认:false
  deep?: boolean
}

以上就是详解Vue中Computed与watch的用法与区别的详细内容,更多关于Vue Computed watch的资料请关注我们其它相关文章!

(0)

相关推荐

  • 如何理解Vue中computed和watch的区别

    概述 我们在 Vue 项目中多多少少都会有用到 computed 和 watch,这两个看似都能实现对数据的监听,但还是有区别.所以以下通过一个小栗子来理解一下这两者的区别. computed 计算属性 计算属性基于 data 中声明过或者父组件传递的 props 中的数据通过计算得到的一个新值,这个新值只会根据已知值的变化而变化,简言之:这个属性依赖其他属性,由其他属性计算而来的. <p>姓名:{{ fullName }}</p> ... ... data: { firstNam

  • 深入浅析Vue中的 computed 和 watch

    computed 计算属性:通过属性计算得来的属性 计算属性,是在相关联的属性发生变化才计算,计算过一次,如果相关属性没有变化,下一次就不需要计算了,直接去缓存的值 a:<input type="number" v-model.number="a" /> b:<input type="number" v-model.number="b" /> <!--c:<input type="

  • vue中computed和watch的使用实例代码解析

    需求: 1.点击按钮实现天气的切换: 2.用watch进行监视天气产生变化的数据: 实现代码(helloworld.vue实现代码): <template> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> </div> &

  • Vue的watch和computed方法的使用及区别介绍

    Vue的watch属性 Vue的watch属性可以用来监听data属性中数据的变化 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="lib/vue.min.js"></script> <script src="lib/vue-router-3

  • vue Watch和Computed的使用总结

    01. 监听器watch (1)作用 watch:用于监听data中的数据变化,只在被监听的属性值发生变化时执行 export default { data() { return { number: 1 } }, watch:{ // 普通监听方法,这里表示监听data中的 number属性 // 第一个参数表示改变后的新值,第二个参数表示改变前的旧值 number(newVal,oldVal){ console.log(newVal); console.log(oldVal); } } } (

  • Vue.js计算属性computed与watch(5)

    在模板中绑定表达式是非常便利的,但是它们实际上只用于简单的操作.模板是为了描述视图的结构.在模板中放入太多的逻辑会让模板过重且难以维护.这就是为什么 Vue.js 将绑定表达式限制为一个表达式.如果需要多于一个表达式的逻辑,应当使用**计算属性**. Vue实例的computed的属性 <div class="test"> <p>原始的信息{{message}}</p> <p>计算后的信息{{ComputedMessage}}</p

  • Vue中computed和watch有哪些区别

    计算属性computed: 支持缓存,只有依赖数据发生改变,才会重新进行计算 不支持异步,当computed内有异步操作时无效,无法监听数据的变化 computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed 如果computed属性属性值是函数,那么默认会走get方法:函数的返回值就是属性的属性

  • 详解Vue中Computed与watch的用法与区别

    目录 computed computed只接收一个getter函数 computed同时接收getter函数对象和setter函数对象 调试 Computed watchEffect 立即执行 监听基本数据类型 停止watchEffect 清理watchEffect watchPostEffect 和 watchSyncEffect watchEffect不能监听对象 watch 监听单个数据 监听多个数据(传入数组) 官方文档总结 computed watchEffect watch comp

  • 详解vue中computed 和 watch的异同

    一.computed 和 watch 都可以观察页面的数据变化.当处理页面的数据变化时,我们有时候很容易滥用watch. 而通常更好的办法是使用computed属性,而不是命令是的watch回调. 这里我直接引用vue官网的例子来说明: html: 我们要实现 第三个表单的值 是第一个和第二个的拼接,并且在前俩表单数值变化时,第三个表单数值也在变化 <div id="myDiv"> <input type="text" v-model="

  • 详解vue中$nextTick和$forceUpdate的用法

    1.$nextTick vm.$nextTick( [callback] ) this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行,在修改数据之后立即使用它,然后等待 DOM 更新.它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上. 应用场景: 1. 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中. 2. 因为在created()钩子函数执行的时候DOM 其实并未

  • 详解Vue中的watch和computed

    前言 对于使用Vue的前端而言,watch.computed和methods三个属性相信是不陌生的,是日常开发中经常使用的属性.但是对于它们的区别及使用场景,又是否清楚,本文我将跟大家一起通过源码来分析这三者的背后实现原理,更进一步地理解它们所代表的含义. 在继续阅读本文之前,希望你已经具备了一定的Vue使用经验,如果想学习Vue相关知识,请移步至官网. Watch 我们先来找到watch的初始化的代码,/src/core/instance/state.js export function in

  • 详解vue中v-for和v-if一起使用的替代方法template

    目录 版本 目标效果 说明 解决方法 核心代码片段 Car.vue vue中v-for和v-if一起使用的替代方法template 版本 vue 2.9.6element-ui: 2.15.6 目标效果 说明 在 vue 2.x 中,在一个元素上同时使用 v-if 和 v-for 时,v-for 会优先作用 解决方法 选择性地渲染列表,例如根据某个特定属性(category )来决定不同展示渲染,使用计算属性computed 见https://www.jb51.net/article/24717

  • 详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法

    最近在项目中实现在循环出来的图片中当鼠标移入隐藏当前图片显示另一张图片的需求时碰到了一个小问题.就是当使用@mouseenter 和@mouseleave事件来实现这个需求时却发现鼠标移入后图片出现闪烁现象. 重点:事件写到父元素上才行!!! 0.0 下面写下我的实现方法和实现效果 样式代码: <div class="imgs" v-for="(item,index) in exampleUrl" :key = index @mouseenter ="

  • 详解Vue中的MVVM原理和实现方法

    下面由我阿巴阿巴的详细走一遍Vue中MVVM原理的实现,这篇文章大家可以学习到: 1.Vue数据双向绑定核心代码模块以及实现原理 2.订阅者-发布者模式是如何做到让数据驱动视图.视图驱动数据再驱动视图 3.如何对元素节点上的指令进行解析并且关联订阅者实现视图更新 一.思路整理 实现的流程图: 我们要实现一个类MVVM简单版本的Vue框架,就需要实现一下几点: 1.实现一个数据监听Observer,对数据对象的所有属性进行监听,数据发生变化可以获取到最新值通知订阅者. 2.实现一个解析器Compi

  • 详解vue中v-on事件监听指令的基本用法

    一.本节说明 我们在开发过程中经常需要监听用户的输入,比如:用户的点击事件.拖拽事件.键盘事件等等.这就需要用到我们下面要学习的内容v-on指令. 我们通过一个简单的计数器的例子,来讲解v-on指令的使用. 二. 怎么做 定义数据counter,用于表示计数器数字,初始值设置为0 v-on:click 表示当发生点击事件的时候,触发等号里面的表达式或者函数 表达式counter++和counter--分别实现计数器数值的加1和减1操作 语法糖:我们可以将v-on:click简写为@click 三

  • 详解vue中v-model和v-bind绑定数据的异同

    vue的模板采用DOM模板,也就是说它的模板可以当做DOM节点运行,在浏览器下不报错,绑定数据有三种方式,一种是插值,也就是{{name}}的形式,一种是v-bind,还有一种是v-model.{{name}}的形式比较好理解,就是以文本的形式和实例data中对应的属性进行绑定.比如: var app = new Vue({ el: '#app', template: '<div @click="toggleName">{{name}}</div>', data

  • 详解Vue中Axios封装API接口的思路及方法

    一.axios的封装 在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中.他有很多优秀的特性,例如拦截请求和响应.取消请求.转换json.客户端防御XSRF等. 在一个项目中我们如果要使用很多接口的话,总不能在每个页面都写满了.get()或者.post()吧?所以我们就要自己手动封装一个全局的Axios网络模块,这样的话就既方便也会使代码量不那么冗余. 安装 > npm install axios //这个

随机推荐