#author("2022-05-12T08:58:41+08:00","default:Admin","Admin")
#author("2022-05-14T11:17:20+08:00","default:Admin","Admin")
[[Vue]]

&color(red){※前提条件:本情報はVue 2.0を基づいて説明してる};
#contents

*概要 [#y1858077]

一个对象、键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

#codeprettify{{
<body>
<div id="app">
    <input type="text" v-model="num">
</div>
<script src="vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            num: ''
        },
        watch: {
            num(newVal, oldVal) {
            // 监听 num 属性的数据变化
    		// 作用 : 只要 num 的值发生变化,这个方法就会被调用
    		// 第一个参数 : 新值
    		// 第二个参数 : 旧值,之前的值
                console.log('oldVal:',oldVal)
                console.log('newVal:',newVal)
            }
        }
    })
</script>
</body>
}}

- immediate(立即处理 进入页面就触发)
- deep(深度监听)
对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch。这时我们需要进行深度监听,就需要加上一个属性 deep,值为 true

#codeprettify{{
<body>
<div id="app">
    <input type="button" value="更改名字" @click="change">
</div>
<script src="vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            food: {
                id: 1,
                name: '冰激凌'
            }
        },
        methods: {
            change() {
                this.food.name = '棒棒糖'
            }
        },
        watch: {
        	// 第一种方式:监听整个对象,每个属性值的变化都会执行handler
        	// 注意:属性值发生变化后,handler执行后获取的 newVal 值和 oldVal 值是一样的
            food: {
                // 每个属性值发生变化就会调用这个函数
                handler(newVal, oldVal) {
                    console.log('oldVal:', oldVal)
                    console.log('newVal:', newVal)
                },
                // 立即处理 进入页面就触发
                immediate: true,
                // 深度监听 属性的变化
                deep: true
            },
            // 第二种方式:监听对象的某个属性,被监听的属性值发生变化就会执行函数
            // 函数执行后,获取的 newVal 值和 oldVal 值不一样
            'food.name'(newVal, oldVal) {
                console.log('oldVal:', oldVal)   // 冰激凌
                console.log('newVal:', newVal)   // 棒棒糖
            }
        }
    })
</script>
</body>
}}

* Watch和computed的区别 [#reaae8b6]

- computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作
- computed不支持异步,当computed内有异步操作时无效,无法监听数据的变化,而watch支持异步
- computed属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值;而watch监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值
- 如果一个属性是由其它属性计算而来的,这个属性依赖其它属性,多对一或者一对一,一般用computed;而当一个属性发生变化时,需要执行对应的操作,一对多,一般用watch

* 监测时handler新值和旧值一样 [#q5c6636b]

** 现象 [#m8dda539]
下面的代码,console打印出来,newValue 和 oldValue 的值一样

#codeprettify{{
<div id="app">
    <h4>a的值是\{\{numbers.a\}\}</h4>
    <input type="button" value="n++" @click="numbers.a++">
</div>
<script>
    const vm = new Vue({
            el: "#app",
            data: {
                numbers : {
                    a : 0,
                    b : 0
                }
            },
            watch: { // 监视属性
                numbers : {
                    handler(newValue, oldValue) {
                        console.log("numbers对象里面的a被修改了!", newValue.a, oldValue.a);
                    },
                    deep : true
                }
            }
        })
</script>    
}}

** 原因 [#u9ca1461]

在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本

** 解决方案 [#ff412356]

想要得到差异内容,可以结合计算属性、序列化、反序列化生成新的对象( numbersNew ),来避免此问题

#codeprettify{{
computed: {
  numbersNew() {
    return JSON.parse(JSON.stringify(this.numbers));
    }
  },
watch: { // 监视属性
  numbersNew: {
    handler(newValue, oldValue) {
           console.log("numbers对象里面的a被修改了!", newValue, oldValue);
    },
    deep: true
   }
 }
}}

#hr();
コメント:
#comment_kcaptcha

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS