浅析setup sugar:使用与不使用 script setup 的繁杂性对比、具体如何使用 script setup、setup存在的限制(配置项缺失的处理)

一、使用与不使用 script setup 的对比

1、不使用 script setup 的繁杂性

  我们之前的组件可能是这样的:

<template>
  <div>
    <Card>{{msg}}</Card>
  </div>
</template>
<script lang="ts">
import { ref, defineComponent } from "vue";
import Card from "./components/Card.vue";

export default defineComponent({
  components: {
    Card,
  },
  setup() {
    const msg = ref("setup script");
    return { msg };
  }
});
</script>

  这里做了两件事,一个是导入并注册组件,一个是导出一个字符串给template使用。

  如果模板上要使用的这些变量,必须要在 setup 返回的对象中定义。暴露变量必须 return 出来,如果我们内容很多的话,那么这个 setup 就会返回很多值,动辄十几二十行,也是挺繁琐的。有没有更简单的办法,于是 script setup 语法出现。使用这个语法只需要在 script 标签上加上 setup 属性。

2、script setup 使用:启用setup script之后是这样的

  vue3.2 将这个之前的实验功能变为正式功能,在单文件组件中引入了一种新的脚本类型:< script setup >

<script lang="ts" setup>
import { ref } from "vue";
import Card from "./components/Card.vue";
const msg = ref("setup script");
</script>

  这里省去了组件的注册步骤,也没有显式的导出变量的动作。你只需要在script上配置setup即可。

<script setup>
  import { ref } from 'vue'
  // 像在平常的setup中code,但是不需要返回任何变量
  const count = ref(0)//在此处定义的count可以直接在模板html中引用
  const inc = () => {//函数也可以直接引用,而不用返回
    count.value++
  }
</script>
<template>
  <Foo :count="count" @click="inc" />
</template>

  当 <script> 标签具有 setup 属性时,组件在编译的过程中代码运行的上下是 setup() 函数中。所有ES模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。

  其实 script setup 就相当于在编译运行是把代码放到了 setup 函数中运行,然后把导出的变量定义到上下文中,并包含在返回的对象中。

二、如何使用 script setup 语法

1、导出变量和方法:在setup script里面定义的所有变量都会自动导出,非常方便。

2、使用组件:所有的组件导入即可自动注册。

  需要注意一点的是:如何定义组件名 => name?

  在 script setup 中,引入的组件可以直接使用,无需再通过components进行注册,并且无法指定当前组件的名字,它会自动以文件名为主

  如果需要定义类似 name 的属性,可以再加个平级的 script 标签,在里面实现即可。

3、使用 props - defineProps:使用 props 需要用到defineProps来定义,具体用法跟之前的 props 写法类似。

  通过 defineProps 指定当前 props 类型的同时,获得上下文的props对象

  在 script中 需要 props[key] 引用,而 template 中可直接调用 key。

<script lang="ts" setup>
import { defineProps } from "vue";
const props = defineProps(['title', 'content']);
</script>

// 给props定义类型:
const props = defineProps({
  title: String,
  content: {
      type: Stirng,
      required: true
  }
});

// 使用TS的注解的方式:
defineProps<{
  title?: string
  content: string
}>();

4、使用 emits - defineEmit:使用defineEmit定义当前组件含有的事件,并通过返回的上下文去执行 emit

  使用 defineEmit 对组件里面使用到的事件进行验证和定义,具体用法跟之前一样。

const emit = defineEmit(['onHeaderClick'])
emit('onHeaderClick', 'params')

// 还可以对事件进行验证
const emit = defineEmit({
    onHeaderClick: ({title}) => {
        if(!title) {
            console.warn('Invalid title')
            return false
        }
        return true
    }
})

5、使用 context - useContext:使用 useContext 获取上下文。

  可以通过useContext从上下文中获取 slots 和 attrs。不过提案在正式通过后,废除了这个语法,被拆分成了useAttrsuseSlots

import { useContext } from 'vue'
const { slots, attrs } = useContext()
// 获取到的slots attrs跟之前的setup里面的是一样的。

6、使用Slots和Attrs:需要useSlots, useAttrs

<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
</script>

7、指令:指令跟组件一样,导入自定注册。

<script setup>
  import {color as superColor} from './v-color'
</script>

<template>
  <div v-super-color />
</template>
// 导入的 color 重命名为 superColor,并自动映射为指令v-super-color

8、defineExpose API

  传统的写法,我们可以在父组件中,通过 ref 实例的方式去访问子组件的内容,但在 script setup 中,该方法就不能用了,setup 相当于是一个闭包,除了内部的 template 模板,谁都不能访问内部的数据和方法。

  如果需要对外暴露 setup 中的数据和方法,需要使用 defineExpose API。示例:

<script setup>
import { defineExpose } from 'vue'
const a = 1
const b = 2
defineExpose({
    a
})  // 将 a 暴露出去
</script>

三、setup 目前存在的限制

1、配置项的缺失:修改选项配置需要单开一个 script

  有时候我们需要更改组件选项,在 setup 中我们目前是无法做到的。我们需要在上方再引入一个 script,在上方写入对应的 export 即可。

<script>
   export default {
       name: 'YourName',
       inheritAttrs: false,
       customOptions: {},
   } 
</script>
<script setup>
  // your code
</script>

  注意:Vue 3 SFC 一般会自动从组件的文件名推断出组件的 name。在大多数情况下,不需要明确的 name 声明。唯一需要的情况是当你需要 <keep-alive> 包含或排除或直接检查组件的选项时,你需要这个名字。

posted @ 2021-10-15 16:21  古兰精  阅读(1353)  评论(0编辑  收藏  举报