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

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

文章目录

侦听器

前言

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

基本示例

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

html 复制代码
<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上。例如:

html 复制代码
<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中的键设置为用.分隔的路径(即对象嵌套中的路径),可以将上方的代码这样写:

html 复制代码
<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值才可以触发。例如:

html 复制代码
<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按钮:

html 复制代码
<button @click="some.nested = 'b?'">点我</button>

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

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

html 复制代码
<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:

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

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

一次性侦听器

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

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

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

相关推荐
web1350858863516 分钟前
前端node.js
前端·node.js·vim
m0_5127446417 分钟前
极客大挑战2024-web-wp(详细)
android·前端
若川26 分钟前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点41 分钟前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
m0_748256563 小时前
如何解决前端发送数据到后端为空的问题
前端
请叫我飞哥@3 小时前
HTML5适配手机
前端·html·html5
@解忧杂货铺5 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
F-2H7 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++