vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.85k stars 549 forks source link

<script setup>语法糖对于部分情况的解构赋值不友好 #383

Closed languanghao closed 2 years ago

languanghao commented 2 years ago

假设.vue页面需要使用到一个实例,对象定义如下

class Preson {
    name = 'anna'

    age = 20   

    say = () => {
        ...
    }
}

在原先使用setup函数的时候,可以简单的使用下面的写法使得Person对象的属性在template中被访问到

setup() {
    return {
        ...new Person()
    }
}
<temlate>
    <div>{{ name }} </div>
   <div>{{ age }} </div>
</template>

现在使用 <script setup>的时候,必须在页面中重新定义一次这些属性名字,当模板需要用到比较多属性或者方法的时候,会显得非常麻烦

<script setup>
     const { name,  age,  say } = ...new Person()
</script>

希望能够引入一种方法解决这个问题,可能的解决方案是引入一个类似 defineExpose 的宏,比如 defineReturn,通过defineReturn({...new Person()}),将展开的属性自动带入到template中

pangao66 commented 2 years ago

I have the same question

yyx990803 commented 2 years ago

既然你在用 <script setup>,那就意味着你的组件里除了 Person 之外还有别的属性。用 spread 把多个这样的对象混在一起意味着跟 mixin 一样会导致属性来源不清晰的问题:

return {
  ...a,
  ...b,
  ...c
}
<div>{{ name }}</div>

这里光看这个组件本身你根本不知道 name 是哪里来的,这对于长期维护和类型推导都不友好。另外你这个 Person 也不是响应式的,你这么用你的 class 也不能触发更新,即使用了 reactive(new Person()) 也不行,因为你把它 spread 的时候 this 就不对了。

反过来看

<script setup>
     const { name,  age,  say } = usePerson()
     const { x, y, z } = useOtherFeature()
</script>

<template>
  <div>{{ name }}</div>
</template>

这里 name 是哪里来的清清楚楚,类型明确,还可以定义跳转来查看具体实现。usePerson() 可以通过返回 ref 来保证触发更新。

如果要用 Composition API,就不要再拘泥于 class 和 this 的思维模式。尤其是 <script setup> 里根本不存在 this,模版就是当前作用域里的一个函数。建议遵循最佳实践。