vue3.0 watch侦听器

目录

  • 前言:
  • 1.选项式 API 中的侦听器
    • 1.1函数式侦听器
    • 1.2对象式侦听器
    • 1.3对象式侦听器相关参数
      • 1.3.1deep
      • 1.3.2immediate
      • 1.3.3flush
    • 1.4this.$watch 侦听器
      • 1.4.1 创建侦听
      • 1.4.2 停止侦听
  • 2.组合式 API 中的侦听器
    • 2.1 watch()函数
      • 2.1.1创建侦听
      • 2.1.2 停止侦听
    • 2.2 watchEffect()函数
      • 2.2.1 回调的触发时机
      • 2.2.2 停止侦听
    • 2.3 watch和watchEffect的对比
      • 2.3.1 watch
      • 2.3.2 watchEffect
  • 总结

前言:

今天给大家讲解的是vue3.0中watch侦听器的使用及语法,看完文章希望能够帮助到你!


1.选项式 API 中的侦听器

在选项式 API 中,我们可以使用watch选项在每次响应式属性发生变化时触发一个函数

1.1函数式侦听器

  • 在watch选项中声明的函数即为函数式侦听器,其中函数名就是要侦听的数据源,函数中的参数1为新数据值,参数2为旧数据值
<script>
export default {
    data: () => ({
        age: 30, // 年龄
        emp: {
            name: 'Jack', // 名字
            salary: 7000 // 薪水
        }
    }),
    // 侦听器
    watch: {
        /**
         * 侦听 age 数据源是否发生变化
         * @param {*} newData 新值
         * @param {*} oldData 旧值
         */
        age(newData, oldData) {
            console.log('newData: ' + newData)
            console.log('oldData: ' + oldData)
        },
        /**
         * 侦听 emp.name 数据源是否发生变化(通过采用字符串路径的形式来侦听对象中的某一个属性)
         * @param {*} newData 新值
         * @param {*} oldData 旧值
         */
        'emp.name'(newData, oldData) {
            console.log('newData: ' + newData)
            console.log('oldData: ' + oldData)
        }
    }
}
</script>

<template>
    年龄:<input type="number" v-model="age">
    <hr>
    员工的名字:<input type="text" v-model="emp.name">
</template>

1.2对象式侦听器

  • 在watch选项中声明的对象即为对象式侦听器,对象名就是要侦听的数据源,其中对象里的handler函数为数据源发生变化后需要执行的代码块,其参数1为新数据值,参数2为旧数据值
<script>
export default {
    data: () => ({
        age: 30, // 年龄
        emp: {
            name: 'Jack', // 名字
            salary: 7000 // 薪水
        }
    }),
    // 侦听器
    watch: {
        // 侦听 age 数据源
        age: {
            /**
             * 如果 age 数据源发生变化,将执行handler的代码片段
             * @param {*} newData 新值
             * @param {*} oldData 旧值
             */
            handler(newData, oldData) {
                console.log('newData: ' + newData)
                console.log('oldData: ' + oldData)
            }
        },
        // 侦听 emp.name 数据源
        'emp.name': {
            /**
             * 如果 emp.name 数据源发生变化,将执行handler的代码片段
             * @param {*} newData 新值
             * @param {*} oldData 旧值
             */
             handler(newData, oldData) {
                console.log('newData: ' + newData)
                console.log('oldData: ' + oldData)
            }
        }
    }
}
</script>

<template>
    年龄:<input type="number" v-model="age">
    <hr>
    员工的名字:<input type="text" v-model="emp.name">
</template>

1.3对象式侦听器相关参数

1.3.1deep

watch默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数,而嵌套属性的变化不会触发
如果想侦听所有嵌套的变更,你需要深层侦听器deep: true选项
深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大

watch: {
        // 侦听 emp 对象数据源
        emp: {
            // 默认的浅层次的侦听器:只有侦听的数据源的值发生变化时,才会触发 handler 函数,而改变侦听的数据源中的嵌套属性值并不会出发该函数
            handler(newData, oldData) {
                console.log('员工的新旧值:')
                console.log(newData)
                console.log(oldData)
            }
        },
        student: {
            deep: true, // 深度侦听:如果改变侦听对象中的嵌套属性值,也会触发 handler 函数,但是 newData 和 oldData 是相等的
            // 只有改变侦听对象的值时,newData 和 oldData 才是不相等的
            handler(newData, oldData) {
                console.log('学生的新旧值:')
                console.log(newData)
                console.log(oldData)
            }
        }
    },;

1.3.2immediate

watch 默认是懒执行的:仅当数据源变化时,才会执行回调;但在某些场景中,我们希望在创建侦听器时,
立即执行一遍回调,可采用immediate: true选项

watch: {
        account: {
            // 默认形况下,侦听器懒执行的:仅当数据源变化时,才会执行回调
            handler(newData, oldData) {
                console.log('账号的新旧值:')
                console.log(newData)
                console.log(oldData)
            }
        },
        student: {
            deep: true,
            immediate: true, // 创建侦听器时立即执行一次该 handler 函数
            handler(newData, oldData) {
                console.log('学生的新旧值:')
                console.log(newData)
                console.log(oldData)
            }
        }
    }

1.3.3flush

默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用;这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。
如果想在侦听器回调中能访问被 Vue 更新之后的DOM,你需要指明flush: 'post’选项

 watch: {
        account: {
            handler(newData, oldData) {
                console.log('账号的新旧值:')
                console.log(newData)
                console.log(oldData)
                // 侦听器默认情况下,回调函数中访问 Dom 将是更新之前的状态
                console.log(document.getElementById('titleAccount').innerHTML)
            }
        },
        password: {
            flush: 'post', // 更改回调的触发机制(Dom 更新后)
            handler(newData, oldData) {
                console.log('密码的新旧值:')
                console.log(newData)
                console.log(oldData)
                // 回调函数中访问 Dom 将是更新之后的状态
                console.log(document.getElementById('titlePassword').innerHTML)
            }
        }
    }

1.4this.$watch 侦听器

1.4.1 创建侦听

使用组件实例的 $watch()方法来命令式地创建一个侦听器;它还允许你提前停止该侦听器
语法:this.$watch(data, method, object)
 	1. data:侦听的数据源,类型为String
	2. method:回调函数,参数一新值,参数二旧值
	3. object:配置
		a. deep:深度侦听
    	b. immediate:创建时立即触发
    	c. flush: 'post':更改回调机制(DOM更新后)
<script>
export default {
    data: () => ({
        account: 'Abc', // 账号
        emp: {
            name: 'Jack', // 名字
            salary: 7000 // 薪资
        },
        student: {
            name: 'Annie', // 名字
            age: 18 // 年龄
        }
    }),
    // 声明周期函数:页面成功渲染后
    mounted() {
        // 通过组件的实例调用$watch函数来创建侦听器

        // 语法:this.$watch(data, method, object)
        // 1. data:侦听的数据源,类型为String
        // 2. method:回调函数,参数一新值,参数二旧值
        // 3. object:配置
            //   a. deep:深度侦听
            //   b. immediate:创建时立即触发
            //   c. flush: 'post':更改回调机制(DOM更新后)
        this.$watch('account', (newData, oldData) => {
            console.log('账号的新旧值:')
            console.log(newData)
            console.log(oldData)
        })

        this.$watch('emp.salary', (newData, oldData) => {
            console.log('薪资的新旧值:')
            console.log(newData)
            console.log(oldData)
        }, { immediate: true })


        this.$watch('student', (newData, oldData) => {
            console.log('学生的新旧值:')
            console.log(newData)
            console.log(oldData)
            console.log(document.getElementById('titleAge').innerHTML)
        }, { deep: true, flush: 'post' })
    }
}
</script>

<template>
    账号:<input type="text" v-model="account">
    <hr>
    薪资:<input type="numner" v-model="emp.salary">
    <hr>
    <h3 id="titleAge">
        学生年龄:<span>{{ student.age }}</span>
    </h3>
    学生年龄:<input type="numner" v-model="student.age">
</template>

1.4.2 停止侦听

需要自行停止侦听器,这时可以调用$watch() API 返回的函数
<script>
export default {
    data: () => ({
        account: 'Abc', // 账号
        stopAccountWatch: null // 调用该函数,可以停止侦听账号数据源
    }),
    // 声明周期函数:页面成功渲染后
    mounted() {
        this.stopAccountWatch = this.$watch('account', (newData, oldData) => {
            console.log('账号的新旧值:')
            console.log(newData)
            console.log(oldData)
        })
    }
}
</script>

<template>
    账号:<input type="text" v-model="account">

    <button @click="stopAccountWatch">停止侦听账号数据源</button>
</template>';

2.组合式 API 中的侦听器

在组合式API中,我们可以使用watch函数或者watchEffect函数在每次响应式状态发生变化时触发对应的回调函数

2.1 watch()函数

2.1.1创建侦听

语法:watch(source, callback, options)
1. source:需要侦听的数据源,可以是ref(包括计算属性)、一个响应式对象、一个 getter函数、或多个数据源组成的数组
2. callback:回调函数
	a. 侦听单个数据源:回调函数的第一个参数为新值,第二个参数为旧值
	b. 侦听多个数据源组成的数组:一个参数数组是新值,第二个参数数组是旧值
3. options:配置,Object类型
	a. deep: true:深度侦听,一般用在侦听的是getter函数返回的对象
	b. immediate: true:创建好侦听器立即执行
 	c. flush: 'post':更改回调的触发机制(Dom更新后)
<script setup>
// 引入 watch 函数
import { ref, reactive, watch } from 'vue'

// 账号
let account = ref('Abc')

// 员工
let emp = reactive({
   name: 'Jack',
   salary: 7000
})

// 密码
let password = ref('123456')

// 侦听:创建完侦听器后立即执行一边
watch(
   account,
   (newData, oldData) => {
       console.log('===== 账号 =====')
       console.log(newData)
       console.log(oldData)
   },
   // 创建完侦听器后立即执行一边
   { immediate: true }
)

// deep: true:深度侦听,侦听函数返回的对象时,其嵌套属性值发生变换,依然可以触发回调函数,但是 newData, oldData 是相等的
watch(
   () => emp,
   (newData, oldData) => {
       console.log('===== 员工 =====')
       console.log(newData)
       console.log(oldData)
   },
   // 深度侦听
   { deep: true }
)

watch(
   password,
   (newData, oldData) => {
       console.log('===== 密码 =====')
       console.log(newData)
       console.log(oldData)
       // 默认情况下回调的触发机制在Dom更新之前执行
       console.log(document.getElementById('titlePassword').innerHTML)
   },
   // 更改回调函数的触发机制(Dom更新之后)
   { flush: 'post' }
)
// 侦听:多个数据源组成的数组
watch(
   // 侦听多个数据源组成的数组
   [account, () => emp.salary, dept],
   // 参数一:新值数组,参数二:旧值数组
   ([newAccount, newSalary, newDept], [oldAccount, oldSalary, oldDept]) => {
       console.log('===== 账号新旧值 =====')
       console.log(newAccount)
       console.log(oldAccount)
       console.log('===== 薪资新旧值 =====')
       console.log(newSalary)
       console.log(oldSalary)
       console.log('===== 部门新旧值 =====')
       console.log(newDept)
       console.log(oldDept)
   }
)
</script>

<template>

   账号:<input type="text" v-model="account">
   <hr>
   员工薪资:<input type="number" v-model="emp.salary">
   <hr>
   <h1 id="titlePassword">
       密码:
       <i>{{ password }}</i>
   </h1>
   密码:<input type="password" v-model="password">

</template>

2.1.2 停止侦听

停止侦听器:调用watch()返回的函数即可
<script setup>
// 引入 watch 函数
import { ref, watch } from 'vue'

// 账号
let account = ref('Abc')

// 停止侦听器:调用 watch 返回的函数即可
let stopAccountWatch = watch(
    account,
    (newData, oldData) => {
        console.log('===== 账号 =====')
        console.log(newData)
        console.log(oldData)
    }
)
</script>

<template>

    账号:<input type="text" v-model="account">

    <button @click="stopAccountWatch">停止账号侦听器</button>

</template>

2.2 watchEffect()函数

watchEffect()会立即执行一遍回调函数,如果这时函数产生了副作用,Vue 会自动追踪副作用的依赖关系,自动分析出响应源

<script setup>
// 引入 watch 函数
import { reactive, ref, watchEffect } from 'vue'

// 账号
let account = ref('Abc')

// 员工
let emp = reactive({
    name: 'Jack',
    salary: 7000
})

// 创建成功后立即执行一遍
watchEffect(() => {
    // 此处用到了数据源,如果该数据源的值发生了变化,会重新执行该回调函数
    console.log('账号:' + account.value)
    console.log('员工的薪资:' + emp.salary)
})

</script>

<template>
    账号:<input type="text" v-model="account">
    <hr>
    员工薪资:<input type="number" v-model="emp.salary">
</template>

2.2.1 回调的触发时机

默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用;这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。
如果想在侦听器回调中能访问被 Vue 更新之后的DOM,你需要指明flush: ‘post’ 选项,或者你也可以使用更方便的别名watchPostEffect()函数

<script setup>
import { onMounted, reactive, ref, watchEffect, watchPostEffect } from 'vue'

// 账号
let account = ref('Abc')

// 密码
let password = ref('123456')

// 员工
let emp = reactive({
    name: 'Jack',
    salary: 7000
})

// 当视图渲染成功后
onMounted(() => {
    // 侦听账号
    watchEffect(() => {
        console.log('-------------------------------------')
        console.log('账号:' + account.value)
        // 默认情况下,回调触发机制:在 Dom 更新之前
        console.log(document.getElementById('titleAccount').innerHTML)
    })

    // 侦听密码
    watchEffect(
        () => {
            console.log('=====================================')
            console.log('密码:' + password.value)
            // 默认情况下,回调函数触发机制:在 Dom 更新之前
            console.log(document.getElementById('titlePassword').innerHTML)
        },
        // 更改回调函数触发机制:在 Dom 更新之后
        { flush: 'post' }
    )

    // 侦听薪资
    watchPostEffect(() => {
        console.log('=====================================')
        console.log('员工薪资:' + emp.salary)
        // 回调函数的触发机制:在 Dom 更新之后
        console.log(document.getElementById('titleSalary').innerHTML)
    })
})
</script>

2.2.2 停止侦听

要手动停止一个侦听器,请调用watchEffect或watchPostEffect()返回的函数

<script setup>
import { ref, watchEffect, watchPostEffect } from 'vue'

// 账号
let account = ref('Abc')

// 密码
let password = ref('123456')

// 调用 watchEffect 返回的函数,可以停止该侦听器
let stopWacthAccount = watchEffect(() => {
    console.log('-------------------------------------')
    console.log('账号:' + account.value)
})

// 调用 watchPostEffect 返回的函数,可以停止该侦听器
let stopWacthPassword = watchPostEffect(() => {
    console.log('=====================================')
    console.log('密码:' + password.value)
})

</script>

<template>
    账号:<input type="text" v-model="account">
    <button @click="stopWacthAccount">停止账号侦听器</button>
      
    <hr>
      
    密码:<input type="text" v-model="password">
    <button @click="stopWacthPassword">停止密码侦听器</button>
</template>

2.3 watch和watchEffect的对比

2.3.1 watch

1. watch显式指定依赖数据,依赖数据更新时执行回调函数
2. 具有一定的惰性lazy 第一次页面展示的时候不会执行,只有数据变化的时候才会执行
(设置immediate: true时可以变为非惰性,页面首次加载就会执行)
3. 监视ref定义的响应式数据时可以获取到原值
4. 既要指明监视的属性,也要指明监视的回调

2.3.2 watchEffect

1. watchEffect自动收集依赖数据,依赖数据更新时重新执行自身
2. 立即执行,没有惰性,页面的首次加载就会执行
3. 无法获取到原值,只能得到变化后的值
4. 不用指明监视哪个属性,监视的回调中用到哪个属性就监视哪个属性

总结

以上就是Vue3.0 中watch侦听器的使用方法。希望本篇文章能够帮助到你,不懂得可以评论区或者私信问我,我也会一 一解答。谢谢观看!
我的其他文章:https://blog.csdn.net/m0_60970928?type=blog

你可能感兴趣的:(vue3.0,前端,javascript,vue.js)