【Vue3】第四部分 计算属性和监视

本文详细介绍了Vue3中的计算属性和监视功能。通过示例代码展示了如何使用computed创建响应式计算属性,包括简写和完整写法,并解释了setter的用法。同时,详细探讨了watch监视的六种情况,包括对ref和reactive定义的数据进行不同方式的监视,以及遇到的问题和解决方案。最后,对比了watch和watchEffect的区别,强调watchEffect关注回调函数中的依赖。

【Vue3】第四部分 计算属性和监视



4. 计算属性和监视

4.1 计算属性(computed)


具体代码

<template>
  <div>
      姓:<input type="text" v-model="person.firstname"><br>
      名:<input type="text" v-model="person.lastname"><br>
      全名:<input type="text" v-model="person.fullname">
  </div>
</template>

<script>
import { reactive,computed } from 'vue'
export default {
  name:'TestDemo',
  setup(){

    const person = reactive({
      firstname:'张',
      lastname:'三'
    })

    //计算属性(简写)
    // let fullname = computed(()=>{
    //   return person.firstname + '-' + person.lastname
    // })

    //计算属性(完整写法)
    person.fullname = computed({
      get(){
        return person.firstname + '-' + person.lastname
      },
      set(value){
          const nameArr = value.split('-')
          person.firstname = nameArr[0]
          person.lastname = nameArr[1]
      }
    })


    return{
      person
    }
  }
}
</script>

<style>

</style>

4.2 watch监视(六种情况)

具体代码

<template>
  <div>
    <h1>计数:{{sum}}</h1>
    <button @click="sum++">点击我+1</button>
    <hr>
    <h1>{{message}}</h1>
    <button @click="message+='!'">点击我加!</button>
    <hr>
    <h1>姓名:{{person.name}}</h1>
    <h1>年龄:{{person.age}}</h1>
    <h1>薪资:{{person.job.salary}}K</h1>
    <button @click="person.job.salary++">点击我加薪</button>
    <button @click="person.name+='~'">点击我加~</button>
    <button @click="person.age+=1">点击我加年龄</button>
  </div>
</template>

<script>
import {reactive, ref, watch} from "vue"
export default {
  name:'TestDemo',
  setup(){
    let sum = ref(0)
    let message = ref('你好啊')
    let person = reactive({
      name:'张三',
      age:18,
      job:{
        salary:16
      }
    })

    /* 
        watch
          - 第一个参数:监视对象
          - 第二个参数:回调函数
          - 第三个参数:配置项
    */

    /* 情况一:监视ref所定义的响应式数据(一个) */
    watch(sum,(newval,oldval)=>{
      console.log("sum的值发生变化!",newval,oldval);
    },{immediate:true})


    /* 情况二:监视ref所定义的多个响应式数据(多个) */
    watch([sum,message],(newval,oldval)=>{
      console.log("监视多个响应式数据发生变化",newval,oldval);
    },{immediate:true})

    /* 
      情况三:监视reactive定义的响应式数据(对象)
          出现的小问题:
            - 强制开启深度监视(deep配置失效)
            - 此处没有办法正确获取到oldval
    */
    watch(person,(newval,oldval)=>{
      console.log("person的值发生了变化!",newval,oldval);
    },{immediate:true,deep:true})  //deep配置无效

    /* 
        情况四:监视reactive定义的响应式数据(某一个属性)
        监视reactive中的某个属性需要写成函数
        可以正确获取到oldval
     */
    watch(()=>person.age,(newval,oldval)=>{
      console.log("person下的age发生变化",newval,oldval);
    },{immediate:true})

    /* 
        情况五:监视reactive定义的响应式数据(多个属性)
        可以正确获取到oldval
    */
    watch([()=>person.age,()=>person.name],(newval,oldval)=>{
      console.log("监视reactive下多个属性",newval,oldval);
    },{immediate:true})

    /* 
      情况六: 监视reactive定义的响应式数据中的某个属性,这个属性的值依然还是对象
        - 需要开启深度监视,这里深度监视是起作用的
        - 但是依旧是不能正确获取到oldval
    */
    watch(()=>person.job,(newval,oldval)=>{
      console.log("监视reactive中属性,该属性依然是一个对象",newval,oldval);
    },{immediate:true,deep:true})

    /* 
        总结来说:
          - 只要是监视对象类型的都拿不到oldval的值
            并且会强制开启深度监视
          - 如果想要获取oldval就将它单独拿出来用
    */

    return {
      sum,
      message,
      person
    }
  }
}
</script>

<style>

</style>

4.3 watchEffect函数

watch:既要指明监视的属性,也要指明监视的回调

watchEffect:不需要监视哪个属性,监视的回调中使用了哪个属性就监视哪个属性watchEffect关注的是回调函数的函数体,所以不需要写返回值

import {reactive, ref, watch, watchEffect} from "vue"
export default {
  name:'TestDemo',
  setup(){
    let sum = ref(0)
    let message = ref('你好啊')
    let person = reactive({
      name:'张三',
      age:18,
      job:{
        salary:16
      }
    })

    watch(sum,(newval,oldval)=>{
      console.log("sum的值发生变化",newval,oldval);
    })


    watchEffect(()=>{
      const x = person.job.salary
      const y = person.name
      console.log("监视数据",x,y);
    })


    return {
     sum,
     message,
     person
    }
  }
}

总结

以上就是今天要讲的内容,本文介绍了 计算属性和监视的使用方法和注意点,希望对大家有所帮助!!!

<think>在Vue 3中,计算属性(computed)通常是同步的,并且它们的值是基于其依赖项立即计算的。因此,在计算属性内部直接使用`nextTick`并不常见,因为计算属性的设计是响应式依赖变化并立即更新值。 但是,如果你确实需要在计算属性中使用`nextTick`(例如,在计算属性中执行一些DOM操作,这些操作需要在Vue更新DOM之后进行),你可以通过返回一个函数或者使用其他模式来实现。 需要注意的是,计算属性应该是一个纯函数,并且不应该有副作用(如操作DOM)。所以,如果你需要在计算属性中使用`nextTick`,可能意味着你的设计需要调整。 不过,为了回答你的问题,我们可以这样实现: 1.计算属性中,我们返回一个函数,这个函数内部使用`nextTick`。 2. 或者,在计算属性中,我们调用一个方法,该方法在`nextTick`中执行操作。 但是请注意,在计算属性中直接进行DOM操作或执行副作用是不推荐的。通常,我们会使用`watch`或`watchEffect`来监视计算属性的变化,并在那里使用`nextTick`。 下面是一个示例,展示如何在计算属性变化后使用`nextTick`: ```vue <template> <div ref="myElement">{{ myValue }}</div> </template> <script> import { ref, computed, watch, nextTick } from &#39;vue&#39;; export default { setup() { const count = ref(0); const myElement = ref(null); // 计算属性 const myValue = computed(() => { return count.value * 2; }); // 监听计算属性的变化,然后在nextTick中操作DOM watch(myValue, async (newValue, oldValue) => { // 等待DOM更新 await nextTick(); // 现在DOM已经更新,可以安全地访问DOM console.log(&#39;DOM updated. Element:&#39;, myElement.value); // 进行DOM操作,例如: if (myElement.value) { myElement.value.style.color = &#39;red&#39;; } }); return { count, myValue, myElement }; } }; </script> ``` 在上面的例子中,我们使用`watch`来监听计算属性`myValue`的变化。当`myValue`变化时,我们使用`nextTick`确保DOM已经更新,然后进行DOM操作。 如果你坚持要在计算属性内部使用`nextTick`,你可以这样做(但不推荐): ```javascript const myValue = computed(() => { const doubled = count.value * 2; // 在计算属性内部使用nextTick,但注意:这会在每次计算属性重新计算时执行 nextTick().then(() => { console.log(&#39;Next tick after computed property update&#39;); // 这里可以执行一些操作,但注意:计算属性可能会频繁重算,所以这里的操作可能会被多次触发 }); return doubled; }); ``` 但是,这种写法会导致每次计算属性重新计算时都会执行`nextTick`中的回调,这可能会造成性能问题或不可预期的行为。因此,我们强烈建议使用`watch`来监听计算属性的变化,并在`watch`回调中使用`nextTick`。 **解释:** - 计算属性主要用于基于响应式数据派生新的值,它应该是同步且没有副作用的。 - `nextTick`用于在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用它,然后等待DOM更新。 - 在计算属性中直接使用`nextTick`并不符合计算属性的设计初衷,因为它可能会引入副作用(如操作DOM)或异步行为,而计算属性应该是同步的纯函数。 - 因此,更合适的做法是使用`watch`来监听计算属性(或原始数据)的变化,然后在`watch`回调中使用`nextTick`来确保DOM已经更新。 如果你有特定的使用场景,请提供更多细节,以便给出更精确的解决方案。 §§相关问题§§: 1.Vue3中,计算属性侦听器(watch)有什么区别? 2. 为什么在计算属性中不推荐执行有副作用的操作? 3.Vue3中,如何使用`watchEffect`来监听响应式数据的变化? 4. `nextTick`在Vue3中的工作原理是什么? </think>在 Vue 3 中,直接在计算属性中使用 `nextTick()` 是不常见的模式,因为计算属性本质上是同步的派生值。不过,如果你需要在计算属性触发的 DOM 更新后执行操作,可以通过组合 API 实现。以下是正确用法解释: ### 推荐方案:使用 watch + nextTick ```vue <script setup> import { ref, computed, watch, nextTick } from &#39;vue&#39; const count = ref(0) const elementRef = ref(null) // 计算属性 const doubled = computed(() => count.value * 2) // 监听计算属性变化 watch(doubled, async (newVal) => { await nextTick() // 等待DOM更新 console.log(&#39;DOM已更新,元素高度:&#39;, elementRef.value?.offsetHeight) }) </script> <template> <div ref="elementRef">{{ doubled }}</div> <button @click="count++">增加</button> </template> ``` ### 不推荐但可能的用法(直接嵌入计算属性): ```javascript const doubled = computed(() => { const result = count.value * 2 nextTick(() => { console.log(&#39;DOM更新后执行&#39;) }) return result }) ``` ### 原因解释: 1. **计算属性的同步特性** 计算属性必须是同步函数且立即返回值,`nextTick` 的异步回调会在计算完成后执行,但: - ✅ 不会阻塞计算过程 - ❌ 违反计算属性"纯函数"原则(产生副作用) - ❌ 每次重算都会触发新回调(可能造成多次执行) 2. **DOM 更新时机问题** 当计算属性导致模板变化时,Vue 的更新是异步的: ```mermaid sequenceDiagram 计算属性更新->> DOM渲染队列: 推入更新任务 DOM渲染队列->> nextTick回调: 所有同步任务完成后执行 ``` 3. **替代方案优势** `watch + nextTick` 组合: - 明确分离数据派生(computed)副作用操作 - 精确控制回调触发频率(可添加额外条件) - 符合 Vue 响应式设计原则 ### 使用场景建议: | 场景 | 推荐方案 | |------|----------| | 计算后读取 DOM 尺寸 | watch + nextTick | | 计算后聚焦输入框 | watch + nextTick | | 无 DOM 操作的纯计算 | 单独使用 computed | | 需要等待第三方库初始化 | watch + nextTick | ### 重要注意事项: 1.计算属性中直接调用 `nextTick` 会导致: - 每次依赖变更都产生新回调 - 难以控制回调执行顺序 - 内存泄漏风险(未清理的回调) 2. 使用 `await nextTick()` 时: ```javascript watch(doubled, async () => { await nextTick() // 正确等待 // 此处DOM已更新 }) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值