【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>

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

相关推荐
萧行之1 小时前
Ubuntu Node.js 版本管理工具 n 完整安装与使用教程
linux·前端
IT 行者6 小时前
Web逆向工程AI工具:JSHook MCP,80+专业工具让Claude变JS逆向大师
开发语言·javascript·ecmascript·逆向
devlei7 小时前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
程序员 沐阳8 小时前
JavaScript 内存与引用:深究深浅拷贝、垃圾回收与 WeakMap/WeakSet
开发语言·javascript·ecmascript
Jagger_8 小时前
周末和AI肝了两天,终于知道:为什么要把AI当做实习生
前端
weixin_456164838 小时前
vue3 子组件向父组件传参
前端·vue.js
沉鱼.449 小时前
第十二届题目
java·前端·算法
Setsuna_F_Seiei9 小时前
CocosCreator 游戏开发 - 多维度状态机架构设计与实现
前端·cocos creator·游戏开发
Bigger9 小时前
CodeWalkers:让 AI 助手化身桌面宠物,陪你敲代码的赛博伙伴!
前端·app·ai编程
cyclv10 小时前
无网络地图展示轨迹,地图瓦片下载,绘制管线
前端·javascript