【vue.js】文档解读【day 5】 |侦听器

在这里插入图片描述

如果阅读有疑问的话,欢迎评论或私信!!

侦听器

前言

在computed计算属性中,我们知道如果需要计算“衍生值”:通过监听已有的响应式数据,得到一个新的属性。但是在计算属性中,vue不推荐直接修改属性的值,或者使得其他DOM变化,那么如果我们确实需要产生一些使其他DOM变化时,vue为我们提供了watch侦听器。

基本示例

为了页面更加简介,在演示前先将下面案例中会反复使用的getAnswer函数贴在这里:

<script>
methods: {
    async getAnswer() {
      this.loading = true  //禁止input输入框输入新的数据
      this.answer = 'Thinking...'
      try {
        const res = await fetch('https://yesno.wtf/api')
        this.answer = (await res.json()).answer
      } catch (error) {
        this.answer = 'Error! Could not reach the API. ' + error
      } finally {
        this.loading = false  //处理完成后允许input输入新数据
      }
    }
  }
</script>

使用属性值表示watch值

我们使用watch侦听器时,只需要像computed计算属性一样将方法名绑定在DOM上。例如:

<template>
	<p>Ask a yes/no question:
        <input v-model="question" :disabled="loading" />
    </p>
	<p>{{ answer }}</p>
</template>

<script>
export default {
  data() {
    return {
      question: '',  //将question声明为属性值,不声明的话在watch中无法监听
      answer: 'Questions usually contain a question mark. ;-)',
      loading: false  //设置input的disabled属性,初始值可输入
    }
  },
  watch: {
    // 每当 question 改变时,这个函数就会执行
    question(newQuestion, oldQuestion) { //监听question属性的变化
      if (newQuestion.includes('?') && newQuestion!=oldQuestion) { 
          // watch中可以监听newQuestion新值和oldQuestion旧值属性
          
         //当question中输入新的值时,调用getAnswer方法
        this.getAnswer()
      }  
    }
  },
  
}
</script>

在该案例中,是一个很好的根据DOM中值变化时修改其他DOM中的值的案例。

使用路径表示watch值

同时,watch选项支持把watch中的键设置为用.分隔的路径(即对象嵌套中的路径),可以将上方的代码这样写:

<template>
	<p>Ask a yes/no question:
        <input v-model="some.nested.question" :disabled="loading" />
    </p>
	<p>{{ answer }}</p>
</template>

<script>
export default {
  data() {
    return {
     some:{
        nested:{
          question:''}
      },  //将question声明为属性值,不声明的话在watch中无法监听
      answer: 'Questions usually contain a question mark. ;-)',
      loading: false  //设置input的disabled属性,初始值可输入
    }
  },
  watch: {
    // 每当 question 改变时,这个函数就会执行
    'some.nested.question'(newQuestion, oldQuestion) { //监听question属性的变化
      if (newQuestion.includes('?') && newQuestion!=oldQuestion) { 
          // watch中可以监听newQuestion新值和oldQuestion旧值属性
          
         //当question中输入新的值时,调用getAnswer方法
        this.getAnswer()
      }  
    }
  }
}
</script>

深层侦听器

watch 默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数——而嵌套属性的变化不会触发。如果想侦听所有嵌套的变更,你需要深层侦听器。

拿上述场景举例:如果监听的是nested而不是question,那么如果只是修改quesiotn值是不会触发监听事件,只有修改整个nested值才可以触发。例如:

<template>
	<p>Ask a yes/no question:
        <input v-model="some.nested.question" :disabled="loading" />
        <button @click="some.nested.question = 'b?'">点我</button>
    </p>
	<p>{{ answer }}</p>
</template>

<script>
export default {
  data() {
    return {
     some:{
        nested:{
          question:''}
      },  //将question声明为属性值,不声明的话在watch中无法监听
      answer: 'Questions usually contain a question mark. ;-)',
      loading: false  //设置input的disabled属性,初始值可输入
    }
  },
  watch: {
    // 每当 question 改变时,这个函数就会执行
    'some.nested'(newQuestion, oldQuestion) { //监听question属性的变化
      if (newQuestion.includes('?') && newQuestion!=oldQuestion) { 
          // watch中可以监听newQuestion新值和oldQuestion旧值属性
          
         //当question中输入新的值时,调用getAnswer方法
        this.getAnswer()
      }  
    }
  }
}
</script>

在上面代码中,我们不应该使用newQuestion.includes(‘?’),因为这里newQuestion是一个对象,而不是字符串。但是我们运行会发现并没有报错,也就是根本没有引起侦听。

在未使用deep深层监听器时,我们修改input值不会引起watch的变化。当修改nested整个对象时才会引起侦听事件,修改button按钮:

<button @click="some.nested = 'b?'">点我</button>

修改button之后我们要注意这里会抛出一个异常,这是正常的,因为我们这个代码需要使用includes(‘?’),而newQuestion是一个对象。由此我们也可以确定确实出发了监听事件。

在修改button之后才会引起侦听事件,那么如果想要不修改整个对象引起侦听就要使用deep,例如:

<template>
	<p>Ask a yes/no question:
        <input v-model="some.nested.question" :disabled="loading" />
        <button @click="some.nested.question = 'b?'">点我</button>
    </p>
	<p>{{ answer }}</p>
</template>

<script>
export default {
  data() {
    return {
     some:{
        nested:{
          question:''}
      },  //将question声明为属性值,不声明的话在watch中无法监听
      answer: 'Questions usually contain a question mark. ;-)',
      loading: false  //设置input的disabled属性,初始值可输入
    }
  },
  watch: {
    // 每当 question 改变时,这个函数就会执行
    'some.nested'(newQuestion, oldQuestion) { //监听question属性的变化
      if (newQuestion.question.includes('?')) { 
          // watch中可以监听newQuestion新值和oldQuestion旧值属性
          
         //当question中输入新的值时,调用getAnswer方法
        this.getAnswer()
      }deep:true
    }
  }
}
</script>

在该代码中,可以正常监听some.nested的变化。但是需要注意的是我们这里删除了newQuestion!=oldQuestion,因为官方文档中提到了:

// 注意:在嵌套的变更中,

// 只要没有替换对象本身,

// 那么这里的 newValueoldValue 相同

可以自己尝试添加之后在该代码前进行console进行调试。

即时回调的侦听器

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。

例如上面场景下,我们想在代码执行之前先运行a?,那么我们可以使用和deep同样的属性immediate: true:

<script>
watch: {
    // 每当 question 改变时,这个函数就会执行
    "some.nested": {
      handler(newQuestion, oldQuestion) {
      
        if (newQuestion.question.includes("?")) {
          
          this.getAnswer();
        }
      },
      immediate:true
    },
  },
</script>

回调函数的初次执行就发生在 created 钩子之前。Vue 此时已经处理了 datacomputedmethods 选项,所以这些属性在第一次调用时就是可用的。关于生命周期到后面会详细解释。

一次性侦听器

immediatedeep类似的属性还有once,它设置该侦听器的执行次数,例如:

watch: {
    // 每当 question 改变时,这个函数就会执行
    "some.nested": {
      handler(newQuestion, oldQuestion) {
      
        if (newQuestion.question.includes("?")) {
          
          this.getAnswer();
        }
      },
      once: true
    },
  },
</script>

在侦听一次变化之后就不会再侦听后续的变化。

  • 31
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小井

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值