vue中的watch的用法总结

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。

1、常规用法

<template>
    <div>
        <input v-model="question">
        <span>{{ copyQuestion }}</span>
    </div>
</template>

<script>
export default {
    data() {
        return {
            question: 'Hello World',
            copyQuestion: ''
        };
    },
    watch: {
        question: function (value) {
            this.copyQuestion = value;
        }
        // 下面可以简写,键值一体,键为question,值为question()方法
        // question(value) {
        //     this.copyQuestion = value;
        // }
        // 此外,下面可以监听新旧值的
        // question(newValue, oldValue) {
        //     .......
        // }
    }
};
</script>

注意:使用watch基本用法时有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。

2、绑定方法

<template>
    <div>
        <input v-model="question">
        <span>{{ copyQuestion }}</span>
    </div>
</template>

<script>
export default {
    data() {
        return {
            question: 'Hello World',
            copyQuestion: ''
        };
    },
    watch: {
        // 键为question,值为’handleQuestion()方法,每次监听到question变化,'handleQuestion()方法就会执行一次
        question: 'handleQuestion'
    },
    methods: {
        handleQuestion(value) {
            this.copyQuestion = value;
        }
    }
};
</script>

注意:双向绑定的值(v-model="message"和data() {return
{message}})和watch监听的键要保持一致,同为message

3、deep + handler

当需要监听一个对象的改变时,基本的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。

原因:受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue转换它,这样才能让它是响应的。

<template>
    <div>
        <input v-model="deepQuestion.a.b">
        <span>{{ copyQuestion }}</span>
    </div>
</template>

<script>
export default {
    data() {
        return {
            deepQuestion: {
                a: {
                    b: 'deep question'
                }
            },
            copyQuestion: ''
        };
    },
    watch: {
        deepQuestion: {
            handler: 'handleQuestion',
            deep: true
        }
    },
    methods: {
        handleQuestion(value) {
            this.copyQuestion = value.a.b;
        }
    }
};
</script>

默认情况下 watch方法只监听data中的对象,而无法监听到对象内部属性的改变,此时就需要deep属性对对象进行深度监听。(默认:deep:false)

这样只会给对象的某个特定的属性加监听器。数组(一维、多维)的变化不需要通过深度监听,对象数组中对象的属性变化则需要deep深度监听。

注意到handler了吗,我们给 firstName 绑定了一个handler方法,之前我们写的 watch 方法其实默认写的就是这个handler,Vue.js会去处理这个逻辑,最终编译出来其实就是这个handler。

deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。下面我们使用字符串的形式进行监听优化。

watch: {
  'deepQuestion.a.b': {
    handler(newValue, oldValue) {
      console.log(newValue, oldValue);
    },
    immediate: true,
    // deep: true
  }
} 

只监听对象的某少数个属性值时,可以用对象.属性字符串形式进行监听。

这样Vue.js才会一层一层解析下去,直到遇到属性b,然后才给b设置监听函数。

4、immediate

watch默认情况下在页面首次渲染时,即使监听的值有初始值,也不会直接执行,这种情况下想要第一次渲染后直接监听就需要添加属性:immediate: true

<template>
    <div>
        <input v-model="question">
        <span>{{ copyQuestion }}</span>
    </div>
</template>

<script>
export default {
    data() {
        return {
            question: 'hello question',
            copyQuestion: ''
        };
    },
    watch: {
        question: {
            handler: 'handleQuestion',
            immediate: true
        }
    },
    methods: {
        handleQuestion(value) {
            this.copyQuestion = value;
        }
    }
};
</script>

比如当父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时,也需要执行函数,此时就需要将immediate设为true。
监听的数据后面写成对象形式,包含handler方法和immediate,之前我们写的函数其实就是在写这个handler方法。

5、注销watch

为什么要注销 watch?因为我们的组件是经常要被销毁的,比如我们跳一个路由,从一个页面跳到另外一个页面,那么原来的页面的 watch 其实就没用了,这时候我们应该注销掉原来页面的 watch 的,不然的话可能会导致内置溢出。好在我们平时 watch 都是写在组件的选项中的,他会随着组件的销毁而销毁。如上都是在组件中使用的案例。
但是,如果我们使用下面这样的方式写 watch,那么就要手动注销了,这种注销其实也很简单

const unWatch = app.$watch('text', (newVal, oldVal) => {
  console.log(`${newVal} : ${oldVal}`);
})

unWatch(); // 手动注销watch

app.$watch调用后会返回一个值,就是unWatch方法,你要注销 watch 只要调用unWatch方法就可以了。

6、watch监听路由

    watch: {
        $route: {
            handler: function (to, from) {
                console.log(to); // to表示去往的界面
                console.log(from); // from表示来自于哪个界面
                if (to.path == '/goods/detail') {
                    console.log('货品详情');
                }
            }
        }
    }

或者

// 监听,当路由发生变化的时候执行
watch: {
  $route: {
    handler: function(val, oldVal){
      console.log(val);
    },
    // 深度观察监听
    deep: true
  }
}

或者

// 监听,当路由发生变化的时候执行
watch: {
  '$route':'getPath'
},
methods: {
  getPath(){
    console.log(this.$route.path);
  }
}

(完)

源码解析:Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解

上一篇:python学习路线


下一篇:理解LoadRunner中的局部变量和全局变量