您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Vue 侦听器

本节介绍侦听器 watch 的使用。什么是侦听器,侦听器的特点,以及如何对不同类型的数据进行监听。其中重点掌握对不同类型的数据如何使用侦听器,了解它之后,才能在之后的日常开发中熟练运用。

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

侦听器 watchVue 提供的一种用来观察和响应 Vue 实例上的数据变化的。当被侦听的数据发生变化时,会触发对应的侦听。

前面我们介绍了什么是侦听器 watch,那么如何定义侦听器呢?

侦听器 watch 实际是 vue 实例上的对象。当我们需要对 vue 实例上某个进行侦听时,我们以需要被侦听的名作为 watch 对象的键,以 function 作为该键的值。 function 接收两个参数:侦听数据变化之后的值newValue;侦听数据变化之前的值oldValue

var vm = new Vue({
  el: '#app',
  data() {
    return {
      count: 
    }
  },
  watch: {
    count: function(newVal, oldVal) {
      // 具体处理逻辑
    },
  }
})

解释:
第 5 行,我们在 data 中定义了 Number 类型的数据 count
第 8-12 行,我们在侦听 watch 中定义了侦听器 count

在介绍完如何定义侦听器之后,让我们用几个实例来学习一下如何在项目中使用侦听器。

假设当前项目中有以下需求,的购买商品:

在我们写具体的逻辑之前,让我们先来分析一下如何使用侦听器watch来实现需求:

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body style="background-color: #ccc;">
    <div id="app">
      <div>商品:<input v-model="name"/></div>
      <button v-on:click="cut"></button>
        购买{{count}}
      <button v-on:click="add"></button>
      <button v-on:click="addCart">加入购物车</button>
      <div v-for="(item, index) in list" :key="index">
        {{item.name}}  x{{item.count}}
      </div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script type="text/javascript">
    var vm = new Vue({
      el: '#app',
      data: {
        name: '',
        count:,
        isMax: false,
        list: []
      },
      methods: {
        cut() {
          this.count = this.count - 
          this.isMax = false
        },
        add() {
          this.count = this.count + 
        },
        addCart() {
          this.list.push({
            name: this.name,
            count: this.count
          })
        }
      },
      watch: {
        count: function(newVal, oldVal) {
          if(newVal > ) {
            this.isMax = true
          }
          if(newVal < ) {
            this.count = 
          }
        },
        name: function() {
          this.count = 
          this.isMax = false
        },
        isMax: function(newVal) {
          if (newVal) {
            console.log('注意:您购买的较大,请确认是否操作有误')
          }
        },
        list() {
          console.log('购物车数据发生改变')
        }
      }
    })
  </script>
</html>

解释:
在 html 中, 我们给出商品输入框以及和减少的两个按钮。

第 4-9 行,我们定义了四个数据,分别是:
name — 商品的
count — 商品的
isMax — 是否首次超过 10
list — 购物车列表

第 10-24 行,我们定义了三个,分别是:
cut — 将 count - 1
add — 将 count + 1
addCart — 购物车数据

第 25-49 行,我们定义了四个侦听器,分别是:
name — 对数据 name 侦听,触发时将 count 变成 0;并 将 isMax 变成 false
count — 对数据 count侦听, 检测到 count 大于 10 时,将 isMax 变成 true,检测到 count 小于 0 的时候将 count 为 0。
isMax — 对数据 isMax 侦听,触发时,判断变化后的值是否为 true,当值为 true 时弹出消息
list — 对数据 list 侦听,每次改变时弹出消息。

上面在示例一中学习了对字符串、布尔值、数字、数组类型的侦听,那么如何对对象的某个进行侦听呢?

我们对上述稍作:

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>商品:<input v-model="product.name"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        product: {
          name: ''
        }
      },
      watch: {
        product: function(newValue){
          console.log(newValue)
        }
      }
    })
  </script>
</html>

解释:
第 11-13 行,我们定义来侦听器 product。我们的理想是:当在输入框中输入商品的时候,在控制台中会打印出最新的 product 值。

从图中我们可以看出,实际的执行和我们想象中并不一致。当在输入框中输入商品的时候,侦听器 product 并没有触发。这是为什么呢?我们先带着这个疑问看下下面这段的:

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>商品:<input v-model="product.name"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        product: {
          name: ''
        }
      },
      watch: {
        product: function(newValue){
          console.log(newValue)
        }
      },
       mounted() {
	      this.product = {name: }
	    }
    })
  </script>
</html>

解释:
第 11-13 行,我们定义了侦听器 product,并在生命周期 mountedproduct 的值。运行,我们惊奇地发现侦听器会在一开始的时候触发,输入框中输入的时候同样不会触发。

大部分同学看到这里应该已经猜到之前为什么name不会触发侦听器。因为product指向的是引用地址,在第例子中,我们只了productname,而没有product的引用地址。而在第二个例子中,我们给 product重新赋值,因此product的引用地址也发生了改变,所以可以成功触发侦听器。
通过这个结论,如果只想监听 productname 的变化,可以对进行如下:

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>商品:<input v-model="product.name"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        product: {
          name: ''
        }
      },
      watch: {
        'product.name': function(newValue){
          console.log(newValue)
        }
      }
    })
  </script>
</html>

解释:
第 10-12 行,我们定义了侦听器 product.name,对 productname 进行监听。当 name 值发生变化的时候触发侦听器。

在之前的例子中,我们都是给侦听器赋值,实际上它还可以用对象的形式来定义。

我们给 name 绑定了 handler ,之前我们写的 watch 其实认写的就是这个handler。当 name 发生改变时, handler 就会执行。

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body style="background-color: #ccc;">
    <div id="app">
      <div>商品:<input v-model="name"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        name: '方便面'
      },
      watch: {
	      name: {
	        handler(newVal, oldVal) {
	          console.log(newVal)
	        }
	      }
	    }
    })
  </script>
</html>

解释:
第 7-11 行,我们定义了侦听器 name。它是对象,当 name 发生变化的时候,会 handler 的。。

有时候你可能需要在侦听器最初绑定的时候就触发一次,这个时候我们就需要用到immediate
示例:

<!DOCTYPE html>
  <html lang="en">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>商品:<input v-model="name"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        name: '方便面'
      },
      watch: {
        name: {
          handler(newVal, oldVal) {
            console.log(newVal)
          },
          // 代表在wacth里声明了name这个之后立即先去执行一次handler
          immediate: true
        }
      }
    })
  </script>
</html>

解释:
第 13 行,我们给侦听器 name immediate ,它的值为 true。这个时候,当第一次渲染的时候就会触发侦听器的 handler

在之前的 3.2 中我们学习了如何对对象的某个做侦听:通过指明对象的某个来。假如现在有以下:

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>商品:<input v-model="product.name"/></div>
      <div>商品:<input v-model="product.count"/></div>
      <div>商品:<input v-model="product.title"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        product: {
          name: '',
          count: '',
          title: ''
        }
      },
      watch: {
        'product.name': function(newValue){
          console.log(newValue)
        },
        'product.count': function(newValue){
          console.log(newValue)
        },
        'product.title': function(newValue){
          console.log(newValue)
        }
      }
    })
  </script>
</html>

解释:
watch 中,我们写了三个侦听器,都是针对 product 的某个进行侦听的。那有没有什么更简单的可以实现当 product 里面任何发生变化的时候就执行侦听呢?
这里就需要用到 deepdeep 代表是否深度监听,认值是 false。当设置为 true 时,会对对象里面的每个进行侦听。

示例:

<!DOCTYPE html>
  <html lang="en" style="background-color: #ccc;">
  <head>
    < charset="UTF-8">
    < name="viewport" content="width=device-width, initial-scale=1.0">
    < http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>商品:<input v-model="product.name"/></div>
      <div>商品:<input v-model="product.count"/></div>
      <div>商品:<input v-model="product.title"/></div>
    </div>
  </body>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        product: {
          name: '',
          count: '',
          title: ''
        }
      },
      watch: {
        product: {
          handler: function(newVal) {
            console.log(newVal)
          },
          deep: true
        }
      }
    })
  </script>
</html>

解释:
第 17 行,我们加了 deepdeep的意思就是深入观察,监听器会一层层地往下遍历,给对象的所有都这个监听器,对象里面任何都会触发这个监听器里的 handler。

本节,我们带大家学习了 侦听器watch 在 vue 项目中的运用。主要知识点有以下几点:


联系我
置顶