Vue.js响应式API

1. ref, reactive, toRef, toRefs

  • ref - 创建响应式引用
  • reactive - 创建响应式对象
  • toRef - 创建指向响应式对象属性的引用
  • toRefs - 将响应式对象转换为普通对象(包含 ref)

1.1 ref

  • 作用​:创建一个响应式的引用对象,可以包装基本类型或对象类型。
  • ​特点​
    • 返回一个带有 .value属性的对象
    • 在模板中自动解包(无需使用 .value)
    • 适合包装基本类型值(字符串、数字等)
    • 也可以包装对象,但内部会使用 reactive转换
js 复制代码
import { ref } from 'vue'

// 基本类型
const count = ref(0)
console.log(count.value) // 0

// 对象类型
const user = ref({ name: 'John', age: 30 })
console.log(user.value.name) // John

1.2 reactive

  • 作用​ :创建一个深层次的响应式对象(Proxy 代理)。
    • 特点
    • 只能用于对象类型(对象、数组、Map、Set)
    • 不需要 .value访问
    • 嵌套对象也会被自动转换为响应式
    • 不适合解构(会失去响应性)
js 复制代码
import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: {
    name: 'John',
    age: 30
  }
})

// 直接访问属性
state.count++ // 响应式更新
console.log(state.user.name) // John

1.3 toRef

  • 作用​:为响应式对象的某个属性创建一个 ref,保持与源属性的响应式连接。
  • 特点
    • 保持对源属性的响应式连接
    • 修改 ref 会更新源对象,反之亦然
    • 当需要将 prop 转换为 ref 时特别有用
js 复制代码
import { reactive, toRef } from 'vue'

const state = reactive({
  count: 0
})

// 创建指向 state.count 的 ref
const countRef = toRef(state, 'count')

countRef.value++ // 会更新 state.count
console.log(state.count) // 1

state.count = 10 // 也会更新 countRef.value
console.log(countRef.value) // 10

1.4 toRefs

  • 作用​:将响应式对象的每个属性转换为 ref,保持响应式连接。
  • 特点
    • 解决 reactive 对象解构时失去响应性的问题
    • 返回的对象每个属性都是 ref
    • 在组合函数中返回响应式状态时特别有用
js 复制代码
import { reactive, toRefs } from 'vue'

const state = reactive({
  count: 0,
  name: 'John'
})

// 将响应式对象转换为 ref 对象
const stateRefs = toRefs(state)

// 解构后仍然保持响应性
const { count, name } = toRefs(state)

count.value++ // 会更新 state.count
name.value = 'Alice' // 会更新 state.name

2. computed, watch, watchEffect,

  • computed - 计算属性
  • watch - 侦听器
  • watchEffect - 立即执行侦听器

2.1 computed

  • 作用:创建基于其他响应式数据的派生值,具有缓存机制。
  • 特点
    • 惰性求值:只有依赖变化时才会重新计算
    • 自动追踪依赖
    • 返回一个只读的响应式 ref
    • 适合同步计算
js 复制代码
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

2.2 watch

  • 作用:观察特定数据源的变化,执行回调函数。
  • ​特点​
    • 需要明确指定侦听的数据源
    • 可以获取变化前后的值
    • 支持深度侦听
    • 支持异步操作
    • 可以手动停止侦听
js 复制代码
import { ref, watch } from 'vue'

const count = ref(0)

// 基本用法
watch(count, (newValue, oldValue) => {
  console.log(`count从${oldValue}变为${newValue}`)
})

// 侦听多个源
const name = ref('John')
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
  // 处理变化
})

// 深度侦听对象
const user = ref({ name: 'Alice', age: 30 })
watch(user, (newUser) => {
  console.log('用户信息变化', newUser)
}, { deep: true })

// 立即执行
watch(count, callback, { immediate: true })

2.3 watchEffect

  • 作用:立即执行一个函数,并自动追踪其依赖,依赖变化时重新执行。
  • 特点​
    • 立即执行
    • 自动收集依赖
    • 没有新旧值参数
    • 支持异步操作
    • 可以手动停止
js 复制代码
import { ref, watchEffect } from 'vue'

const count = ref(0)
const name = ref('John')

// 基本用法
watchEffect(() => {
  console.log(`count: ${count.value}, name: ${name.value}`)
})

// 停止侦听
const stop = watchEffect(() => { /* ... */ })
stop() // 停止侦听

// 清理副作用
watchEffect((onInvalidate) => {
  const timer = setTimeout(() => {
    console.log('执行操作')
  }, 1000)
  
  onInvalidate(() => {
    clearTimeout(timer) // 清理操作
  })
})
  • 使用场景
    • 需要立即执行的副作用
    • 依赖关系复杂时
    • 不需要知道具体变化的值时
    • 需要自动收集依赖时

3. shallowRef, shallowReactive

  • shallowRef - 创建浅层响应式引用,只对 .value本身进行响应式处理

    js 复制代码
    import { shallowRef } from 'vue'
    
    const largeObject = shallowRef({ 
      nested: { data: 'value' } // 嵌套对象不会被响应式处理
    })
    
    // 改变顶层属性会触发响应
    largeObject.value = { ... } 
    
    // 改变嵌套属性不会触发响应
    largeObject.value.nested.data = 'new value' // 不会触发更新
  • shallowReactive - 创建浅层响应式对象,只对顶层属性进行响应式处理

    js 复制代码
    import { shallowReactive } from 'vue'
    
    const state = shallowReactive({
      topLevel: 'value',
      nested: { data: 'value' } // 嵌套对象不会被响应式处理
    })
    
    // 改变顶层属性会触发响应
    state.topLevel = 'new value'
    
    // 改变嵌套属性不会触发响应
    state.nested.data = 'new value' // 不会触发更新

4. readonly, shallowReadonly

  • readonly - 创建只读的响应式代理

    • 任何修改尝试都会失败并产生警告
    • 深度只读(所有嵌套属性都是只读的)
    js 复制代码
    import { reactive, readonly } from 'vue'
    
    const original = reactive({ count: 0 })
    const copy = readonly(original)
    
    copy.count++ // 警告:Set operation on key "count" failed
  • shallowReadonly - 创建浅层只读的响应式代理

    • 顶层属性只读
    • 嵌套属性可修改(非只读)
    js 复制代码
    import { shallowReadonly } from 'vue'
    
    const state = shallowReadonly({
      topLevel: 'value',
      nested: { data: 'value' }
    })
    
    state.topLevel = 'new' // 警告:Set operation failed
    state.nested.data = 'new' // 允许修改

5. customRef

  • customRef - 创建自定义的 ref,显式控制依赖追踪和更新触发

    • 提供 track和 trigger函数手动控制
    • 适合实现防抖、节流等高级功能
    js 复制代码
    import { customRef } from 'vue'
    
    function useDebouncedRef(value, delay = 200) {
      let timeout
      return customRef((track, trigger) => {
        return {
          get() {
            track() // 追踪依赖
            return value
          },
          set(newValue) {
            clearTimeout(timeout)
            timeout = setTimeout(() => {
              value = newValue
              trigger() // 触发更新
            }, delay)
          }
        }
      })
    }
    
    // 使用示例
    const text = useDebouncedRef('', 500)

6. effectScope

  • effectScope - 创建一个作用域,可以捕获其中创建的所有响应式 effect

    • 可以统一停止所有 effect
    • 适合在组件作用域外管理 effect
    js 复制代码
    import { effectScope, ref, watch } from 'vue'
    
    const scope = effectScope()
    
    scope.run(() => {
      const count = ref(0)
      
      watch(count, () => {
        console.log('count changed')
      })
      
      // 其他 effect...
    })
    
    // 停止所有 effect
    scope.stop()

7. getCurrentScope, onScopeDispose

  • getCurrentScope - 获取当前活动的 effect 作用域
  • onScopeDispose - 在当前作用域销毁时注册回调函数(在组合式函数中清理资源)
js 复制代码
import { getCurrentScope, onScopeDispose } from 'vue'

function useEventListener(target, event, callback) {
  target.addEventListener(event, callback)
  
  // 如果有当前作用域,注册清理函数
  if (getCurrentScope()) {
    onScopeDispose(() => {
      target.removeEventListener(event, callback)
    })
  }
}

8. provide, inject

依赖注入

9. nextTick

等待下一次 DOM 更新刷新(等DOM更新完成之后,再执行的回调函数)

10. useAttrs, useSlots

  • useAttrs - 访问组件接收的非 props 属性
  • useSlots - 访问组件的插槽内容
js 复制代码
import { useAttrs, useSlots } from 'vue'

const attrs = useAttrs()
const slots = useSlots()

console.log(attrs.class) // 获取 class 属性
console.log(slots.default) // 获取默认插槽

11. defineModel

  • defineModel - 简化自定义组件的双向绑定(v3.4新增)
    • 自动处理 modelValue和 update:modelValue
    • 支持修饰符
js 复制代码
// 子组件
const model = defineModel()

// 父组件
<ChildComponent v-model="value" />

12. withDirectives

  • withDirectives - 在渲染函数中应用自定义指令
js 复制代码
import { withDirectives, h } from 'vue'
import { vTooltip } from './directives/tooltip'

export default {
  render() {
    return withDirectives(h('div'), [
      [vTooltip, 'This is a tooltip']
    ])
  }
}

13. renderList

  • renderList - 高效渲染列表(优化列表渲染性能)
js 复制代码
import { renderList } from 'vue'

export default {
  render() {
    return renderList(items, (item, index) => {
      return h('div', { key: item.id }, item.text)
    })
  }
}

14. resolveComponent, resolveDirective ​调试工具​

  • resolveComponent - 按名称解析已注册的组件
  • resolveDirective - 按名称解析已注册的指令
js 复制代码
import { resolveComponent, h } from 'vue'

export default {
  render() {
    const ButtonComponent = resolveComponent('MyButton')
    return h(ButtonComponent, { onClick: handleClick }, 'Click me')
  }
}

15. onRenderTracked, onRenderTriggered 样式处理​

  • 调试钩子,用于追踪组件的渲染依赖和触发重新渲染的原因(性能分析和调试)
js 复制代码
import { onRenderTracked, onRenderTriggered } from 'vue'

onRenderTracked((event) => {
  console.log('依赖被追踪', event)
})

onRenderTriggered((event) => {
  console.log('重新渲染被触发', event)
})

16. useCssModule, useCssVars

  • useCssModule - 在 <script setup> 中访问 CSS 模块(在组合式 API 中使用作用域 CSS)

    js 复制代码
    import { useCssModule } from 'vue'
    
    const $style = useCssModule()
    
    // 在模板中使用
    <template>
      <div :class="$style.container"></div>
    </template>
  • useCssVars - 在组合式 API 中动态设置 CSS 变量(主题切换和动态样式)

    js 复制代码
    import { useCssVars } from 'vue'
    
    useCssVars((_ctx) => ({
      '--primary-color': theme.value.primary,
      '--secondary-color': theme.value.secondary
    }))
相关推荐
Larcher30 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐43 分钟前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭1 小时前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信1 小时前
我们需要了解的Web Workers
前端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu2 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花2 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋2 小时前
场景模拟:基础路由配置
前端
六月的可乐2 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程