Skip to main content
v-model

Sewen6/26/2024Less than 1 minuteVueVue3Vue3源码分析
侦听器

watch

基础

官方文档:响应式 API:核心 | Vue.js (vuejs.org)

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

详细信息

watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

  • 第一个参数是侦听器的。这个来源可以是以下几种:

    • 一个函数,返回一个值

    • 一个 ref

    • 一个响应式对象

    • ...或是由以上类型的值组成的数组

  • 第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

    • 当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。
  • 第三个可选的参数是一个对象,支持以下这些选项:

    • immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined

    • deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器

    • flush:调整回调函数的刷新时机。参考回调的刷新时机watchEffect()

    • onTrack / onTrigger:调试侦听器的依赖。参考调试侦听器

    • once:回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。

watchEffect() 相比,watch() 使我们可以:

  • 懒执行副作用
  • 更加明确是应该由哪个状态触发侦听器重新执行
  • 可以访问所侦听状态的前一个值和当前值

示例

侦听一个 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]) => {
  /* ... */
})

当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用 { deep: true } 强制侦听器进入深层级模式。在深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。

const state = reactive({ count: 0 })
watch(
  () => state,
  (newValue, oldValue) => {
    // newValue === oldValue
  },
  { deep: true }
)

当直接侦听一个响应式对象时,侦听器会自动启用深层模式:

const state = reactive({ count: 0 })
watch(state, () => {
  /* 深层级变更状态所触发的回调 */
})

watch()watchEffect() 享有相同的刷新时机和调试选项:

watch(source, callback, {
  flush: 'post',
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  }
})

停止侦听器:

const stop = watch(source, callback)

// 当已不再需要该侦听器时:
stop()

副作用清理:

watch(id, async (newId, oldId, onCleanup) => {
  const { response, cancel } = doAsyncWork(newId)
  // 当 `id` 变化时,`cancel` 将被调用,
  // 取消之前的未完成的请求
  onCleanup(cancel)
  data.value = await response
})

Sewen6/26/2024About 8 minVueVue3Vue3源码分析
响应式原理

流程图

Vue3 响应式原理过程与 Vue2 差异不大,主要是将 Vue2中 依赖收集和派发更新的 Watcher 对象替换成了 副作用渲染函数 Effect()


Proxy API

Proxy 响应式实现:


// Proxy 中 receiver: Proxy 或者继承 Proxy 的对象
// Reflect 中 receiver: 如果 target 对象中设置了 getter, getter 中的 this 指向 receiver
const proxy = new Proxy(target,{
	get(target,key,receiver){
 		target[key]
		return Reflect.get(target, key, receiver)
	},
	set(target, key,value,receiver){
    	target[key] = value
      	return  Reflect.set(target, key,value, receiver)
	},
	deleteProperty(target, key){
        delete target[key]
		return Reflect.deleteProperty(target,key)
    }
}

Sewen6/26/2024About 29 minVueVue3Vue3源码分析
指令

Sewen6/26/2024Less than 1 minuteVueVue3Vue3源码分析