和Vue3和解的Day6--侦听器watch

396 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

说点题外话

前面我用了5篇的篇幅说了为什么要更新了vue3, vue3对比vue2的优点,以及底层原理,如何做到数据响应式。

这一篇开始我将全面对vue3学习进行介绍,我会选项式option API 、组合式composition API和setup语法糖三种书写方式。

说正文

image.png

1. 根元素不同

在vue2中只支持一个根元素,但是vue3中支持多个根元素

/** vue2只能存在一个根元素 */
  <template id="my-app">
    <div>
      <a :href="link">百度</a>
      <img :src="img" alt="">
    </div>
  </template>

/** vue3可以存在多个根元素 */
<template id="my-app">
    <a :href="link">百度</a>
    <img :src="img" alt="">
</template>

因为vue3在解析我们模板信息的时候会在根元素的地方自动套上一层标签作为根元素。

2. watch的选项式中

我们知道在选项式中我们响应式的数据会放在data函数里面,这里也说说为什么data一定是个函数呢

  • 我们需要每个vue文件之间的数据是不共享的,这样才能做到组件多次引用也能不互相影响。所以data是一个函数返回一个对象,每次引用组件的时候就会创建赋值一个新的内存地址。
  • 如果data是对象的话,那么每一次组件复用引用的都是同一个内存地址。

2.1 基本使用

watch是个对象,里面定义需要侦听的数据函数

  • 函数接收两个参数: 一个变化后的值和变化前的值
<input type="text" v-model="question">

export default{
  data() {
    return {
      question: "Hello World"
    }
  },
  watch: {
    question(newValue, oldValue) {
      console.log(`新值${newValue},旧值${oldValue}`);
      this.quesClick()
    }
  },
  methods: {
    quesClick() {
    console.log(`你的问题${this.question}的答案是没有答案`)
    }
  }
}

当输入框中的值有改动,就会输出我们打印的值,执行quesClick方法。

2.2 watch侦听对象

    <h2>{{ info.name }}</h2>
    <button @click="changeInfo">改变info</button>
    <button @click="changeInfoName">改变info.name</button>

<script>
export default {
  data() {
    return {
      info: { name: "小白" }
    }
  },

我会根据这个基础框架对watch的其他属性进行详细解释,也方便我们使用composition API

  • 更改整个info对象
  watch: {
    // 侦听整个info对象
    info(newValue, oldValue) {
      console.log("新值:", newValue, "旧值:", oldValue);
    }
  },
  methods: {
    changeInfo() {
      this.info = { name: "小刚" }
    },
    changeInfoName() {
      this.info.name = "小刚"
    }
  },

点击changeInfo后页面展示和输出结果是:页面和输出的值都有进行改变;点击changeInfoName页面的值有改变,但是状态栏没有任何输出。

image.png

这段代码就验证了一点:默认情况下,侦听器只会针对监听的数据本身的改变,内部发生的改变是不能侦听的,我们直接更改对象的属性值,在监听整个对象是侦听不到内部的改变,所以需要我们使用额外的api来完成侦听

所以侦听器又提供给我们三个参数:handledeepimmediate

如果我们需要对对象内部进行侦听,也就是深度侦听,需要使用deep参数来辅助完成


    <h2>{{ info.name }}</h2>
    <button @click="changeInfo">改变info</button>
    <button @click="changeInfoName">改变info.name</button>

<script>

export default {
  data() {
    return {
      info: { name: "小白", friends: { name: "小红" } }
    }
  },
  watch: {
    info: {
      handler: function (newValue, oldValue) {
        console.log("新值:", newValue, "旧值:", oldValue);
      },
      deep: true
    },
  },
  methods: {
    changeInfo() {
      this.info = { name: "小刚" }
      this.info.friends = { name: "change小红" }
    },
    changeInfoName() {
      this.info.name = "小刚"
      this.info.friends.name = "change小红"
    }
  },
}
</script>

依次点击changeInfochangeInfoName之后输出结果分别是

image.png

image.png

我们发现直接更改对象中的属性,新值和旧值都是更改后的值,而我们修改整个对象则不会出现这种情况。这是因为对象是是引用类型,只是提供一个指针,所以对象属性内的值实际上更改的是一个内存地址的值,我们侦测整个对象新值旧值都会是新值。

  watch: {
    "info.name": {
      handler: function (newValue, oldValue) {
        console.log("新值:", newValue, "旧值:", oldValue);
      },
      deep: true
    },
  },
  methods: {
    changeInfo() {
      this.info = { name: "小刚" }
      this.info.friends = { name: "change小红" }
    },
    changeInfoName() {
      this.info.name = "小刚"
      this.info.friends.name = "change小红"
    }
  },

当我们直接改变对象中的属性的时候,直接侦听属性的值,就会获得我们想要获得的结果

image.png

2.3 侦听器的第二种写法

<template>
  <div>
    <h2>{{ info.name }}</h2>
    <button @click="changeInfo">改变info</button>
    <button @click="changeInfoName">改变info.name</button>
  </div>
</template>

<script>

export default {
  data() {
    return {
      info: { name: "小白", friends: { name: "小红" } }
    }
  },
  mounted() {
    this.$watch("info", (newValue, oldValue) => {
      console.log("新值:", newValue, "旧值:", oldValue);
    },{
      deep: true
    })
  },
  methods: {
    changeInfo() {
      this.info = { name: "小刚" }
      this.info.friends = { name: "change小红" }
    },
    changeInfoName() {
      this.info.name = "小刚"
      this.info.friends.name = "change小红"
    }
  },
}
</script>

侦听器的第二种写法,使用this.$watch侦听:

  • 第一个参数是要侦听的源

  • 第二个参数是侦听的回调函数callback

  • 第三个参数是额外的其他选项:deepimmediate

image.png

说再见

下一篇说侦听器在composition组合式Api中的写法

难忘今宵

喝白开水是最好的补水方法吗?

首先,最简单最有效的补水方法就是直接喝白开水或是矿泉水;另外,各种茶也是补水的好来源;还有一种非常有效的补水方法就是多喝粥汤。