Vue 属性侦听(1)

273 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

Vue 通过 watch 选项来侦听属性的变化,watch 选项中可以编写 watchers(侦听器),每个 watcher 都能侦听到当前活动的实例上对应的数据的变化。

  • 什么是侦听器呢?
    • 开发中我们在 data 返回的对象中定义了数据,这个数据通过插值语法等方式绑定到 template 中;
    • 当数据发生变化时,template 会自动进行更新来显示最新的数据;
    • 但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要通过 watch 选项用侦听器(watchers 来完成了;
  • 侦听器的用法如下:
    • 选项:watch
    • 类型:{ [key: string]: string | Function | Object | Array }(即 watch 是一个对象,对象中的 key 要求是 string 类型,key 对应的 value 可以是 string 类型或Function 类型或Object 类型或 Array 类型)

1. 侦听器基础使用案例

比如用户在 input 中输入一个问题,我们希望根据输入的问题去服务器查询答案。

  • 第一种方式是我们再提供一个查询按钮,用户输入完问题后点击按钮向服务器发送网络请求查询答案。
  • 第二种方式是不提供查询按钮,但每当用户输入了最新的内容,我们就获取到最新的内容,并使用该内容(问题)去服务器查询答案,也就是说我们要实时地获取最新的数据。

第一种方式(<body> 元素中)代码如下:

<div id="app"></div>

<template id="my-app">
  您的问题:<input type="text" v-model="question">
  <button @click="searchAnswer">查找答案</button>
  <p>{{ result }}</p>
</template>

<script src="./js/vue.js"></script>
<script>
  const App = {
    data() {
      return {
        question: '谁是最可爱的人',
        answer: '',
        result: ''
      }
    },
    methods: {
      searchAnswer() {
        // 向服务器发送网络请求,查找答案
        // ...
        // 把服务器返回的答案保存到变量中
        this.answer = '服务器返回的答案'

        this.result = `问题“${this.question}”的答案是:${this.answer}`;
      }
    },
    template: '#my-app'
  };

  Vue.createApp(App).mount('#app');
</script>

页面效果:

侦听器引出案例.gif

上面这种方式中必须点击按钮才会去查找答案,那如果现在的需求是只要用户在 input 中输入了内容,就立刻根据最新的内容去查找答案呢?也就是说我们需要监听 input 中数据的变化,只要其中的数据发生变化就会去查找答案,而不需要再去点击按钮查找。

  • 这时候我们就需要(在代码逻辑中)侦听 dataquestion 的变化了。
    • 在第一种方式中,侦听 dataquestion 的变化是交给 Vue 的响应式系统完成的,响应式系统侦听到变化后会更新 template 中的内容(页面内容);
    • 而现在,我们需要在侦听 dataquestion 的变化时,去进行一些逻辑的处理(如网络请求),而逻辑处理通常是通过 JavaScript 代码实现的,也就是说我们需要在 JavaScript 代码中的某个地方去侦听 question 的变化,怎么侦听呢?这时我们就可以在 watch 选项中进行侦听了。

第二种方式(<body> 元素中)代码如下:

<div id="app"></div>

<template id="my-app">
  您的问题:<input type="text" v-model="question">
  <!-- <button @click="searchAnswer">查找答案</button> -->
  <p>{{ result }}</p>
</template>

<script src="./js/vue.js"></script>
<script>
  const App = {
    data() {
      return {
        question: '谁是最可爱的人',
        answer: '',
        result: ''
      }
    },
    watch: {
      // question:要侦听的数据(data 中返回的对象的属性名称,或者 computed 属性,
      // 当然,还可以侦听 props(用来实现组件之间数据的传递,后面会讲))
      // newValue:变化后的新值
      // oldValue:变化前的旧值
      question(newValue, oldValue) {
        console.log('新值:', newValue, '旧值:', oldValue);
        this.searchAnswer(newValue);
        // 真实开发中可能会使用 axios 发送网络请求:
        // axios.get({
        //   // ...
        // });
        // 后面我们也会对 axios 进行讲解、封装
      }
    },
    methods: {
      searchAnswer(newValue) {
        // 向服务器发送网络请求,查找答案
        // ...
        // 把服务器返回的答案保存到变量中
        this.answer = '服务器返回的答案'

        // this.result = `问题“${this.question}”的答案是:${this.answer}`;
        this.result = `问题“${newValue}”的答案是:${this.answer}`;
      }
    },
    template: '#my-app'
  };

  Vue.createApp(App).mount('#app');
</script>

页面效果:

侦听器案例.gif

因为 input 元素上用 v-model 做了双向绑定(后面讲 v-model 时会讲),所以当 input 中的内容发生变化时,data 中的 question 也会同步变化,而由于我们在 watch 中编写了对 question 的侦听,所以 question 发生变化时,就会执行 question 侦听器中的代码。

总结:当我们想要侦听比如说 data 中的数据,当它发生变化时,我们想进行一些逻辑处理的时候,一般就会使用侦听器;但如果只是页面中的数据(template 中的数据),它本身就能对数据的变化进行响应,不需要使用侦听器。