首页IT科技vue监听watch监听全局对象(Vue3-Watch踩坑-watch监听无效)

vue监听watch监听全局对象(Vue3-Watch踩坑-watch监听无效)

时间2025-08-05 09:07:51分类IT科技浏览5368
导读:ref 与 reactive ref函数和reactive函数都是用来定义响应式数据...

ref 与 reactive

ref函数和reactive函数都是用来定义响应式数据

但是reactive更适合定义引用类型             、ref适合定义基本数据类型(可接收基本数据类型和对象)

reactive

1                    、 深层次响应式             ,本质是将传入的数据包装成一个Proxy对象

2       、 参数必须是对象或者数组                    ,如果要让对象的某个元素实现响应式时       ,需要使用toRefs             ,这样每个都需要采用value方式访问

ref

1      、函数参数可以是基本数据类型                    ,也可以接受对象类型

2                    、如果参数是对象类型时       ,其实底层的本质还是reactive

3              、ref响应式原理是依赖于Object.defineProperty()的get()和set()的

watch

在自身组件监听 reactive 对象

let a = reactive({test: 123, bg: 456, hh: {hhh: 78}}) // 定时器 1 setTimeout(() => { a.test = 456 }, 2000) // 定时器 2 setTimeout(() => { a.hh.hhh = 56 }, 4000) // 定时器 3 setTimeout(() => { a = {} }, 6000) // watch(a, () => { // 定时器1      , 2 可以触发监听                    , 不需要deep也可以 // 定时器3 不能触发监听             , 因为对象的地址已经发生改变了 console.log("change") }) // 函数返回方式 采用deep可以监听, 不加deep不能监听 watch( () => a, () => { console.log(" func change") }, { deep: true } )

为什么不加 deep不能监听呢      ,直接从源码看

function watch(source, cb, options) { if (!isFunction(cb)) { warn2( `\`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, cb, options); } function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ) { // 代码不完整                    ,截取部分 ... if (isRef(source)) { getter = () => source.value; forceTrigger = isShallow(source); } else if (isReactive(source)) { // 这里              ,如果 source 是 reactive // 则 deep = true // 而 deep 为true 后面会 执行traverse getter = () => source; deep = true; } else if (isArray(source)) { isMultiSource = true; forceTrigger = source.some((s) => isReactive(s) || isShallow(s)); 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, 2 /* WATCH_GETTER */); } else { warnInvalidSource(s); } }); } else if (isFunction(source)) { // 如果是函数, //最终 getter () => fn() // deep为false                    ,因此不走 traverse() if (cb) { getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); } else { getter = () => { if (instance && instance.isUnmounted) { return; } if (cleanup) { cleanup(); } return callWithAsyncErrorHandling( source, instance, 3 /* WATCH_CALLBACK */, [onCleanup] ); }; } } else { getter = NOOP; warnInvalidSource(source); } .... if (cb && deep) { const baseGetter = getter; getter = () => traverse(baseGetter()); } }

traverse 深度遍历整个对象                    ,深层次的访问其所有的响应式变量,并收集依赖

在自身组件监听 ref 对象

let a = ref({test: 123, bg: 456, hh: {hhh: 78}}) setTimeout(() => { a.value.test = 456 }, 2000) setTimeout(() => { a.value.hh.hhh = 56 }, 4000) setTimeout(() => { a.value = {} }, 6000) // 注意下面两种写法 一个是 a , 一个是 a.value // 从源码可知             , 如果是 a, 那么走isRef(source)分支                    , 如果是 a.value 那么走 isReactive(分支) // 这里不给出结果       ,动手试试 watch(a.value, (val) => { console.log(val, "change") }) watch(a, (val) => { console.log(val, "change") }) // 如果是 函数返回的方式呢? 其实也分两种             ,类推即可                    ,同时也需要注意是否需要加 deep 属性 watch(() => a.value, (val) => { console.log(val, "change") }) watch(() => a, (val) => { console.log(val, "change") })

如果在子组件需要监听父组件的数据       ,同时父组件可以通过v-model双向绑定时需要非常注意      ,不然可能出现一些bug

如果watch监听无效                    ,根据你的数据结构分析是否是因为写法不正确导致             。

文章来自我个人搭建的博客             ,https://cxid.gitee.io/

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
浏览器url是什么意思(一文通透从输入URL到页面渲染的全过程—-高频面试)