Vue 3 监听属性教程

Vue 3 监听属性教程

1. 什么是监听属性?

在 Vue 3 中,监听属性(Watchers)是一种强大的响应式系统特性,允许您追踪和响应数据变化。Vue 提供了两种主要的监听方法:watch 和 watchEffect

2. 基本 watch 使用方法

2.1 监听单个响应式引用

import { ref, watch } from 'vue'

export default {
  setup() {
    const count = ref(0)

    // 监听 count 变化
    watch(count, (newValue, oldValue) => {
      console.log(`count 从 ${oldValue} 变为 ${newValue}`)
    })

    return { count }
  }
}

2.2 监听多个数据源

import { ref, watch } from 'vue'

export default {
  setup() {
    const firstName = ref('张')
    const lastName = ref('三')

    // 监听多个数据源
    watch([firstName, lastName], ([newFirstName, newLastName], [oldFirstName, oldLastName]) => {
      console.log(`名字从 ${oldFirstName} ${oldLastName} 变为 ${newFirstName} ${newLastName}`)
    })

    return { firstName, lastName }
  }
}

3. 深度监听

3.1 监听对象

import { ref, watch } from 'vue'

export default {
  setup() {
    const user = ref({
      name: '张三',
      age: 25,
      details: {
        city: '北京'
      }
    })

    // 深度监听对象
    watch(user, (newUser) => {
      console.log('用户信息发生变化', newUser)
    }, { deep: true })

    return { user }
  }
}

3.2 监听对象特定属性

import { ref, watch } from 'vue'

export default {
  setup() {
    const user = ref({
      name: '张三',
      age: 25
    })

    // 监听对象的特定属性
    watch(() => user.value.name, (newName, oldName) => {
      console.log(`用户名从 ${oldName} 变为 ${newName}`)
    })

    return { user }
  }
}

4. watchEffect 的使用

watchEffect 是一个更加自动和灵活的监听方法,它会自动收集依赖并在依赖变化时重新执行。

import { ref, watchEffect } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const doubled = ref(0)

    // watchEffect 自动追踪依赖
    watchEffect(() => {
      doubled.value = count.value * 2
      console.log(`count 变化,doubled 现在是 ${doubled.value}`)
    })

    return { count, doubled }
  }
}

5.watchEffect 与 watch 的区别


1.依赖追踪:

watchEffect 自动收集依赖
watch 需要显式指定要监听的数据源
2.初始执行:

watchEffect 会立即执行一次
watch 默认不会在初始化时执行
3.访问旧值:

watch 可以同时获取新值和旧值
watchEffect 只能访问当前值


6. 停止监听

import { ref, watch } from 'vue'

export default {
  setup() {
    const count = ref(0)

    // 创建可停止的监听器
    const stopWatch = watch(count, (newValue) => {
      console.log(`count 变为 ${newValue}`)
    })

    // 在需要时停止监听
    // stopWatch()

    return { count }
  }
}

7.elementplus示例,使用watch普通监听,不使用深度监听

<template>
    <div>
        <el-form :model="customsCargoForm" ref="customsCargoFormRef"  size="default" label-width="120px" inline-message>
        //...省略内容
        </el-form>
        <el-table>
        //...省略内容
        </el-table>
    </div>
</template>
<script lang="ts" setup name="busCustomsIn">
	import { ref,watch, onMounted, reactive, nextTick } from "vue";

	const customsCargoForm = ref<any>({});//form表单
	const customsCargoFormRef = ref();//声明form表单信息对象
	const itemnoNum = ref(1);//项号默认参数
    
    //加载报关货物信息表
	const AssignmentCargo=async()=>{
		cargoloading.value = true;
		const queryParams =({"customsId":saveCustomsId.value});
		var res = await getListBusCustomsCargo(queryParams);
		cargoTableData.value = res.data.result ?? [];
		cargoloading.value = false;
        //修改监听对象的值
		itemnoNum.value = cargoTableData.value.length + 1;
		console.log("cargoTableData.value:",cargoTableData.value)
    });
    
    //新增,编辑,删除,插入数据,修改数据顺序上移下移等会修改cargoTableData.value.length或customsCargoForm.value.itemNo,因为需要动态改变customsCargoForm.value.itemNo的值,因此监听itemNo来改变customsCargoForm.value.itemNo可以减少与接口交互的次数。
    
    //监听属性值的变化(自动停止)
    watch(itemnoNum, (val) => {
        console.log("监听itemnoNum的值改变为:",val)
        customsCargoForm.value.itemNo = val;
        //如果需要同时监听旧值和新值,或监听多个参数,修改该方法的传参即可
        //watch(itemnoNum, (val)=>{});改为watch(itemnoNum, (newValue,oldValue)=>{})
        //console.log(`count 从 ${oldValue} 变为 ${newValue}`)
        //watch([parm], (val)=>{});改为watch([parm1,parm2], ([val1],[val2])=>{});
         //console.log(`parm的值变为val`)
         //console.log(`parm1的值变为val1,parm2的值变为val2`)
    });
</script>

8.注意事项


(1)尽量使用 watch 监听特定数据源
(2)对于复杂的副作用,使用 watchEffect
(3)注意性能,避免过于频繁的监听
(4)在组件卸载时停止不必要的监听器
(5)避免在监听器中修改正在监听的数据源,可能导致无限循环
(6)对于大型对象,使用深度监听时要注意性能开销
(7)使用箭头函数可能会影响 this 的指向