<script lang="ts" setup> // 接受父组件传递的数据 const props = defineProps({ test: { type: String, default: '' } }) // 使用 watch 侦听 props 中的 test 属性 watch( // 这种写法不会侦听到 props 中 test 的变化 props.test, () => { console.log("侦听成功") } ) watch( // 这种写法会侦听到 props 中 test 的变化 () => props.test, () => { console.log("侦听成功") } ) </script>
Utilisation de base de watch#🎜🎜 #
watch() est par défautécoute paresseuse, c'est-à-dire que la fonction de rappel n'est exécutée que lorsque la source d'écoute change#🎜 🎜 #Le premier paramètre : source d'écoute, la source d'écoute peut être l'un des types suivants
Une fonction qui renvoie une valeur, une référence, un objet réactif (réactif) ou se compose des types de valeurs ci-dessus Tableau deLe deuxième paramètre : la fonction de rappel à déclencher lorsque la source d'écoute change.
(newValue, oldValue) => { /* code */}
Lors de l'écoute de plusieurs sources, la fonction de rappel accepte deux tableaux, correspondant aux tableaux sources. La nouvelle valeur et l'ancienne valeur dans
( [ newValue1, newValue2 ] , [ oldValue1 , oldValue2 ]) => code */}
Le troisième paramètre : Objet facultatif, vous pouvez supporter ces options
immediate : Le rappel est déclenché immédiatement lorsque l'écouteur est créé en profondeur : Si la source est un objet, le parcours en profondeur sera forcé pour que la fonction de rappel soit déclenchée lorsque le niveau profond changes flush : Ajustement du timing d'actualisation de la fonction de rappel onTrack / onTrigger : dépendance de l'écouteur de débogage2 Raison
watch
ne peut que. be Les 4 situations ci-dessusconst obj = reactive({ count: 0 }) // 错误,因为 watch() 中的侦听源是一个 number,最终 source 返回的 getter 函数是一个空,所以就得不到侦听的数据 watch(obj.count, (count) => { console.log(`count is: ${count}`) }) // 正确,主要思想是,将侦听源转化为以上4种类型(转化为getter函数是最简单方便的) watch( () => obj.count, (count) => { console.log(`count is: ${count}`) } )
3.watch analyse du code sourcewatch
的侦听源只能是上面的4中情况
export function watch<T = any, Immediate extends Readonly<boolean> = false>( source: T | WatchSource<T>, cb: any, options?: WatchOptions<Immediate> ): WatchStopHandle { if (__DEV__ && !isFunction(cb)) { warn( `\`watch(fn, options?)\` signature has been moved to a separate API. ` + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + `supports \`watch(source, cb, options?) signature.` ) } return doWatch(source as any, cb, options) }
function doWatch( source: WatchSource | WatchSource[] | WatchEffect | object, cb: WatchCallback | null, { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ ): WatchStopHandle { // ... // 当前组件实例 const instance = currentInstance // 副作用函数,在初始化effect时使用 let getter: () => any // 强制触发侦听 let forceTrigger = false // 是否为多数据源。 let isMultiSource = false }
从源码中可以看出,watch
接收三个参数:source
侦听源、cb
回调函数、options
侦听配置,最后会返回一个doWatch
if (isRef(source)) { getter = () => source.value forceTrigger = isShallow(source) }
doWatch
依然接受三个参数:source
侦听源、cb
回调函数、options
侦听配置
这里着重对侦听源的源码进行分析(source标准化)
如果source
是ref
类型,getter
是个返回source.value
的函数,forceTrigger
取决于source
是否是浅层响应式。
if (isReactive(source)) { getter = () => source deep = true }
如果source
是reactive
类型,getter
是个返回source
的函数,并将deep
设置为true
。 当直接侦听一个响应式对象时,侦听器会自动启用深层模式
<template> <div class="container"> <h3>obj---{{ obj }}</h3> <button @click="changeName">修改名字</button> <button @click="changeAge">修改年龄</button> </div> </template> <script lang="ts" setup> import { reactive, watch } from "vue"; const obj = reactive({ name: "张三", age: 18, }); const changeName = () => { obj.name += "++"; }; const changeAge = () => { obj.age += 1; }; // obj 中的任一属性变化了,都会被监听到 watch(obj, () => { console.log("变化了"); }); </script>
例子
if (isArray(source)) { isMultiSource = true forceTrigger = source.some(isReactive) getter = () => source.map(s => { if (isRef(s)) { return s.value } else if (isReactive(s)) { return traverse(s) } else if (isFunction(s)) { return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) } else { __DEV__ && warnInvalidSource(s) } }) }
如果source
是个数组,将isMultiSource
设为true
,forceTrigger
取决于source
是否有reactive
类型的数据,getter
函数中会遍历source
,针对不同类型的source
做不同处理。
if (isFunction(source)) { if (cb) { getter = () => callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER) } else { // watchEffect getter = () => { // 如果组件实例已经卸载,直接return if (instance && instance.isUnmounted) { return } // 如果清理函数,则执行清理函数 if (cleanup) { cleanup() } // 执行source,传入onCleanup,用来注册清理函数 return callWithAsyncErrorHandling( source, instance, ErrorCodes.WATCH_CALLBACK, [onCleanup] ) } } }
如果source
是个function
。存在cb
的情况下,getter
函数中会执行source
,这里source
会通过callWithErrorHandling
函数执行,在callWithErrorHandling
中会处理source
执行过程中出现的错误;不存在cb
的话,在getter
中,如果组件已经被卸载了,直接return
,否则判断cleanup
(cleanup
是在watchEffect
中通过onCleanup
注册的清理函数),如果存在cleanup
执行cleanup
,接着执行source
,并返回执行结果。source
会被callWithAsyncErrorHandling
包装,该函数作用会处理source
执行过程中出现的错误,与callWithErrorHandling
不同的是,callWithAsyncErrorHandling
会处理异步错误。
getter = NOOP __DEV__ && warnInvalidSource(source)
其他情况getter
rrreee
watch
reçoit trois paramètres : source
source d'écoute, fonction de rappel cb
, configuration d'écoute options
, et enfin un doWatch
doWatch
accepte toujours trois paramètres : source
source d'écoute, cb code >Fonction de rappel, <code>options
Configuration de l'écoute#🎜🎜##🎜🎜#Ici on se concentre sur l'analyse du code source de la source d'écoute (#🎜🎜#standardisation de la source#🎜🎜#)#🎜🎜 #source
est de type ref
, getter
est un retour de la fonction de Source.value
, forceTrigger
dépend du fait que source
soit peu réactif. #🎜🎜##🎜🎜##🎜🎜#rrreeesource
est réactif
Tapez, getter
est une fonction qui renvoie source
et définit deep
sur true
. Lors de l'écoute directe d'un objet réactif, l'écouteur active automatiquement le mode profond 2">source
est un tableau, définissez isMultiSource
sur true
, forceTrigger
Selon que source
possède ou non des données de type réactif
, la fonction getter
parcourra source
pour différents types de source
est traité différemment. #🎜🎜##🎜🎜##🎜🎜#rrreeesource
est une fonction
. Lorsque cb
existe, source
sera exécuté dans la fonction getter
, où source
passera callWithErrorHandlingExécution de la fonction, les erreurs qui surviennent lors de l'exécution de <code>source
seront gérées dans callWithErrorHandling
s'il n'y a pas de cb
, dans getter
, si le composant a été désinstallé, directement return
, sinon déterminez cleanup
(cleanup
est dans watchEffect code> (fonction de nettoyage enregistrée via <code>onCleanup
), s'il y a cleanup
, exécutez cleanup
, puis exécutez source code> et renvoyer les résultats de l'exécution. <code>source
sera enveloppé par callWithAsyncErrorHandling
. Cette fonction gérera les erreurs qui se produisent lors de l'exécution de source
, qui est différente de callWithErrorHandling<.> Oui, <code>callWithAsyncErrorHandling
gérera les erreurs asynchrones. #🎜🎜##🎜🎜##🎜🎜#rrreeegetter
se verra attribuer une fonction vide #🎜🎜##🎜🎜##🎜🎜#rrreeeCe qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!