vue中template模版自动解构机制

166 阅读2分钟

一、官方文档

cn.vuejs.org/guide/essen…

二、可以自动解包哪部分的数据

能被自动解包的类型说明是否需要 .value举例
ref 对象自动访问 .value 属性ref(1) 在 template 中直接 {{ count }}
reactive 对象保持响应式代理,不需要特殊处理reactive({ name: 'abc' }),直接 user.name
普通值(基本类型)字符串、数值、布尔直接返回使用const name = 'Vue'{{ name }}
计算属性(computed)自动访问 .value 属性computed(() => count.value * 2)
函数(方法)可以直接调用,不做处理const inc = () => count.value++,直接 @click="inc"
props自动解包传进来的 props<MyComp title="hello" />{{ title }}
emits / attrs / slots通过 context 提供,自动挂到 ctx有条件插槽 slot 可直接用,attrs 通过 $attrs

三、代码示例

  1. ref自动解包
<script setup>
import { ref } from 'vue'

const count = ref(0)

console.log(count.value) // setup中需要写count.value
</script>

<template>
  <p>{{ count }}</p> <!-- 无需 count.value -->
</template>
  1. reactive 保持代理
<script setup>
import { reactive } from 'vue'

const user = reactive({ name: 'Alice' })
</script>

<template>
  <p>{{ user.name }}</p> <!-- user对象是响应式代理 -->
</template>
  1. computed 自动解包
<script setup>
import { computed } from 'vue'

const double = computed(() => 2 * 3)
console.log(double.value) // setup中需要写double.value
</script>

<template>
  <p>{{ double }}</p> <!-- double.value 自动解包 -->
</template>
  1. 方法直接调用
<script setup>
function greet() {
  console.log('Hello!')
}
</script>

<template>
  <button @click="greet">Greet</button>
</template>

  1. props 自动解包
<script setup>
defineProps(['title'])
</script>

<template>
  <h1>{{ title }}</h1> // 无需props.title
</template>

三、自动解包工作原理

  • 通过编译阶段(compiler)识别变量

  • 在运行时,Vue 用 proxyRefs()(Vue内部方法)包装 setup 的返回对象

  • proxyRefs() 逻辑就是:

    • 如果是 ref,访问时自动 .value
    • 如果是其他普通对象,直接返回
function proxyRefs(object) {
  return new Proxy(object, {
    get(target, key) {
      const val = target[key]
      return isRef(val) ? val.value : val
    },
    set(target, key, value) {
      const oldVal = target[key]
      if (isRef(oldVal) && !isRef(value)) {
        oldVal.value = value
        return true
      } else {
        target[key] = value
        return true
      }
    }
  })
}

三、注意⚠️

类型说明要自己手动处理
深层次 ref比如 ref({ a: 1 }),访问 count.a 要小心
复杂嵌套对象ref({ user: { name: 'abc' } })user 不是 proxy
自定义对象/类实例不一定自动解包,除非你手动处理响应式
外部返回的对象某些第三方库(比如 axios)返回的对象,不会响应式