vue3中的computed如何结合v-model使用?

概述

computed 是vue3中响应式系统的核心API,用于创建基于响应式数据变化的派生值. 什么是派生值?可以简单理解为响应式数据相当于河流的主干, 那么computed的结果就是该主干的支流,是由主干派生出来的. 与普通函数不同的是, computed会将结果缓存起来,只有依赖项状态改变后才会重新计算, 提供高效数据转换.

核心特性:

  1. 响应式依赖追踪: 自动检测收集响应式依赖

  2. 惰性计算: 只有在首次执行和依赖项状态变化才会计算

  3. 结果缓存: 依赖项未变化,返回缓存结果

  4. 类型安全: 完美支持 TypeScript类型推断

基本用法

创建只读计算属性

import { ref, computed } from 'vue'
​
const count = ref(0)
​
// 创建只读计算属性
const doubleCount = computed(() => count.value * 2)
​
console.log(doubleCount.value) // 0
​
count.value = 5
console.log(doubleCount.value) // 10 (依赖项变化重新计算)

创建可写计算属性

const firstName = ref('王')
const lastName = ref('五')
​
// 创建可写计算属性
const fullName = computed({
  // getter 函数
  get() {
    return `${firstName.value}${lastName.value}`
  },
  // setter 函数
  set(newValue) {
    // 当设置 fullName 时拆分名字
    const [first, last] = newValue.split(' ')
    firstName.value = first
    lastName.value = last || ''
  }
})
​
// 使用计算属性
console.log(fullName.value) // "王五"
​
// 修改计算属性
fullName.value = '小 明'
console.log(firstName.value) // "小"
console.log(lastName.value)  // "明"

详细介绍

响应原理

  1. 首次访问

    • 执行计算函数

    • 收集函数内访问的响应式依赖

    • 缓存计算结果

  2. 依赖变化

    • 标记计算属性为"脏"(d)

    • 不立即重新计算

  3. 再次访问

    • 检测到 d 标志

    • 重新执行计算函数

    • 更新缓存值

    • 清除 d 标志

参数说明

  1. 可接收一个getter函数, 返回一个只读ref对象,通过ref.value暴露getter函数的返回值. 或者接收一个带有get和set函数的对象,创建一个可写的ref对象.

  2. 接收一个配置对象,用于调试

    const debugComputed = computed(() => {
      // 调试逻辑
      console.log('计算中...')
      return someValue.value * 2
    }, {
      // 调试钩子
      onTrack(e) {
        console.log('依赖被追踪:', e)
      },
      onTrigger(e) {
        console.log('依赖变化触发:', e)
      }
    })

参数类型

// 只读
function computed<T>(
  getter: (oldValue: T | undefined) => T,
  // 查看下方的 "计算属性调试" 链接
  debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>
​
// 可写的
function computed<T>(
  options: {
    get: (oldValue: T | undefined) => T
    set: (value: T) => void
  },
  debuggerOptions?: DebuggerOptions
): Ref<T>

最佳实践

场景1: 数据格式化

const price = ref(99.9)
const formattedPrice = computed(() => `¥${price.value.toFixed(2)}`)

场景2: 数据转换, 数组排序/筛选

const todos = ref([{ id: 1, text: '学习', done: true }])
const activeTodos = computed(() => 
  todos.value.filter(todo => !todo.done)
)

场景3:多状态组合, 基于多个状态计算派生值

const width = ref(100)
const height = ref(50)
const area = computed(() => width.value * height.value)

高级用法

场景: 结合v-model使用

// 父组件
<S v-model="modealData">
  
// 在子组件中
<template>
    <el-input v-model=modelData.value1 />
    <el-select v-model=modelData.value2 />
  </template>
export defualt {
  props: {
    modealData: Object
  },
  setUp(){
    const emit = defineEmits('modelData:update')
    const computedData = computd(() => {
      get(){
        const proxyData = new Proxy(props.modealData, key,{
        get(target, key){
          return Reflect.get(target, key)
        },
        set(target, key ,value){
          emit('modelData:update',{
            ...target,
            [key]: value  
          })
        }
      })
        return proxyData
      },
     set(val){
       emit('modelData:update',val)
     }
    })
  }
}

性能优化策略

  1. 避免复杂计算

    // 不推荐:计算函数过于复杂
    const heavyComputation = computed(() => {
      return largeArray.value.reduce((acc, item) => {
        // 非常复杂的计算逻辑...
      }, 0)
    })
    ​
    // 推荐:将复杂计算拆分为多个计算属性
    const filtered = computed(() => largeArray.value.filter(/* 条件 */))
    const processed = computed(() => filtered.value.map(/* 转换 */))
  2. 避免副作用

    // 错误:计算属性中产生副作用
    const invalidComputed = computed(() => {
      // 禁止:修改外部状态
      someState.value = 'changed'
      // 禁止:发起异步请求
      fetchData()
    })
  3. 创建可复用计算逻辑

    // usePagination.js
    import { computed } from 'vue'
    ​
    export function usePagination(items, pageSize) {
      const currentPage = ref(1)
      
      const totalPages = computed(() => 
        Math.ceil(items.value.length / pageSize.value)
      )
      
      const paginatedItems = computed(() => {
        const start = (currentPage.value - 1) * pageSize.value
        return items.value.slice(start, start + pageSize.value)
      })
      
      return {
        currentPage,
        totalPages,
        paginatedItems
      }
    }
    在组件中使用
    
    import { usePagination } from './usePagination'
    ​
    const items = ref([...]) // 大型数据集
    const pageSize = ref(10)
    ​
    const { currentPage, totalPages, paginatedItems } = usePagination(
      items, 
      pageSize
    )

总结

计算属性是 Vue 响应式编程的核心范式,正确使用可显著提升应用性能与代码可维护性. 当需要基于现有状态派生新值时,computed 应作为首选方案.在使用计算属性时,理解其核心特性是关键.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值