Vue3中必学的customRef数据追踪技巧:通过案例讲解Data、Watch和computed等不同场景下如何正确实现ref计算器。

部分数据来源:ChatGPT

在 Vue3 中, customRef 是一个新的 API,它让我们可以更加灵活地实现自定义的响应式数据追踪逻辑。而在不同的场景下,我们可能需要使用不同的数据追踪逻辑来满足业务需求。下面我们通过一个案例来讲解在 Data、Watch 和 Computed 等场景下如何正确实现 ref 计算器。

案例介绍

我们将实现一个简单的 ref 计算器,在该计算器中,用户可以输入两个数字并选择相应的运算符来进行计算。与一般的计算器相比,我们的计算器会增加一个功能:在结果超过 1000 时,会将结果自动缩小为原来的一半。为了实现这样的功能,我们需要对计算结果进行监听,并在结果超过 1000 时进行转化处理。

Data 场景下的实现

首先我们来看 Data 场景下的实现。在这种情况下,我们可以使用 reactive 方法将 Data 对象包装成可响应式数据,并在其中声明计算结果等属性。同时,我们可以通过 watch 方法对计算结果进行监听,并实现自定义的数据追踪逻辑。以下是示例代码:

<template>
  <div>
    <input v-model.number="num1" />
    <select v-model="operator">
      <option value="+">+</option>
      <option value="-">-</option>
      <option value="*">*</option>
      <option value="/">/</option>
    </select>
    <input v-model.number="num2" />
    <button @click="calculate">Calculate</button>
    <p>Result: {{ result }}</p>
  </div>
</template>

<script>
import { reactive, watch } from 'vue'

export default {
  setup() {
    const data = reactive({
      num1: 0,
      num2: 0,
      operator: '+',
      result: 0
    })

    const calculate = () => {
      switch (data.operator) {
        case '+':
          data.result = data.num1 + data.num2
          break
        case '-':
          data.result = data.num1 - data.num2
          break
        case '*':
          data.result = data.num1 * data.num2
          break
        case '/':
          data.result = data.num1 / data.num2
          break
      }
    }

    watch(() => data.result, (newResult, oldResult) => {
      if (newResult > 1000 && oldResult <= 1000) {
        data.result = newResult / 2
      }
    }, { immediate: true })

    return {
      ...data,
      calculate
    }
  }
}

在上述代码中,我们使用了 reactive 方法将 Data 对象包装成可响应式数据,并声明了计算结果等属性。同时,在 watch 方法中,我们对计算结果进行了监听,并实现了自定义的数据追踪逻辑。具体来说,当计算结果超过 1000 时,我们会将结果自动缩小为原来的一半。

Watch 场景下的实现

接下来我们来看 Watch 场景下的实现。在这种情况下,由于 Watch 的监听器可以返回一个函数,在该函数中我们可以自定义数据追踪逻辑。因此,我们可以直接使用 Watch 方法对计算结果进行监听,并在回调函数中实现自定义的数据追踪逻辑。

以下是示例代码:

<template>
  <div>
    <input v-model.number="num1" />
    <select v-model="operator">
      <option value="+">+</option>
      <option value="-">-</option>
      <option value="*">*</option>
      <option value="/">/</option>
    </select>
    <input v-model.number="num2" />
    <button @click="calculate">Calculate</button>
    <p>Result: {{ result }}</p>
  </div>
</template>

<script>
import { ref, watch } from 'vue'

export default {
  setup() {
    const num1 = ref(0)
    const num2 = ref(0)
    const operator = ref('+')
    const result = ref(0)

    const calculate = () => {
      switch (operator.value) {
        case '+':
          result.value = num1.value + num2.value
          break
        case '-':
          result.value = num1.value - num2.value
          break
        case '*':
          result.value = num1.value * num2.value
          break
        case '/':
          result.value = num1.value / num2.value
          break
      }
    }

    watch(result, (newResult, oldResult) => {
      if (newResult > 1000 && oldResult <= 1000) {
        result.value = newResult / 2
      }
    })

    return {
      num1,
      num2,
      operator,
      result,
      calculate
    }
  }
}

在上述代码中,我们使用了 ref 方法将计算器的各个数据项转化为可响应式数据。同时,我们使用了 Watch 方法对计算结果进行监听,并实现了自定义的数据追踪逻辑。

Computed 场景下的实现

最后,我们来看 Computed 场景下的实现。在这种情况下,我们可以使用 customRef 方法创建一个自定义的 ref,并在其中实现自定义的数据追踪逻辑。

以下是示例代码:

<template>
  <div>
    <input v-model.number="num1" />
    <select v-model="operator">
      <option value="+">+</option>
      <option value="-">-</option>
      <option value="*">*</option>
      <option value="/">/</option>
    </select>
    <input v-model.number="num2" />
    <button @click="calculate">Calculate</button>
    <p>Result: {{ result }}</p>
  </div>
</template>

<script>
import { customRef } from 'vue'

export default {
  setup() {
    const num1 = customRef((track, trigger) => {
      let value = 0

      return {
        get() {
          track()
          return value
        },
        set(newValue) {
          value = newValue
          trigger()
        }
      }
    })

    const num2 = customRef((track, trigger) => {
      let value = 0

      return {
        get() {
          track()
          return value
        },
        set(newValue) {
          value = newValue
          trigger()
        }
      }
    })

    const operator = customRef((track, trigger) => {
      let value = '+'

      return {
        get() {
          track()
          return value
        },
        set(newValue) {
          value = newValue
          trigger()
        }
      }
    })

    const result = customRef((track, trigger) => {
      const calculate = () => {
        switch(operator.value) {
          case '+':
            return num1.value + num2.value
          case '-':
            return num1.value - num2.value
          case '*':
            return num1.value * num2.value
          case '/':
            return num1.value / num2.value
          default:
            return 0
        }
      }

      return {
        get() {
          track()
          return calculate()
        },
        set() {
          // 禁止直接设置 result 的值
        }
      }
    })

    const calculate = () => {
      result.value = result.value  // 触发 result 的 get 操作,从而触发其他 value 的 track 操作
    }

    return {
      num1,
      num2,
      operator,
      result,
      calculate
    }
  }
}
</script>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

正经人_____

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值