一、使用与不使用 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、使用组件:所有的组件导入即可自动注册。

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 对组件里面使用到的事件进行验证和定义,具体用法跟之前一样。

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 获取上下文。

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、需要注意一点的是:如何定义组件名 => name

  script-setup 无法指定当前组件的名字,所以使用的时候以文件名为主。