vue3.0 script setup 必学知识点

294 阅读1分钟

vue3.0 script setup基本使用

在单文件组件(SFC)中引入一个新的 <script> 类型 setup。 它向模板公开了所有的顶层绑定。

组件

组件直接引入即可使用,无需注册

引入的组件可以直接用作自定义组件标签名,类似于JSX中的工作方式

<template>
  <div>
    <Foo />
  </div>
</template>

<!-- 在 script 标签上添加setup属性,以使用 script setup 语法 -->
<script setup>
import Foo from './components/Foo.vue'
</script>

属性和方法

属性和方法无需挂载到对象上再次返回

<template>
  <div>
    <Foo />
    <h2 @click="increment">{{ count }}</h2>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import Foo from './components/Foo.vue'

const count = ref(0)
const increment = () => count.value++
</script>

上述案例会被编译为

// 导入的模板会被抽离到模块级别
import { ref } from 'vue'
import Foo from './components/Foo.vue'

export default {
  setup () {
    const count = ref(0)
    const increment = () => count.value++

    // 这是一个返回h函数的render函数
    // 因为被编译到了setup函数中,所以可以直接访问顶层定义的属性和方法
    return () => ([
      h(Foo, null, ''),
      h('h2', {
        count,
        onClick: increment
      }, count)
    ])
  }
}

props 和 emits

子组件

<template>
  <div>
    <h2>{{ count }}</h2>
    <button @click="$emit('increment')">+1</button>
    <button @click="decrement">-1</button>
  </div>
</template>

<script setup>
// 接收props, 并返回一个对象,可以在js中使用props来获取传入的数据
const props = defineProps({
  count: {
    type: Number,
    default: 0
  }
})

// 声明需要触发的事件,返回一个emit函数,作用和this.$emit 函数的作用域是一致的
const emit = defineEmits(['increment', 'decrement'])

const decrement = () => emit('decrement')
</script>

父组件

<template>
  <div>
    <Foo :count="count" @increment="increment" @decrement="decrement" />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import Foo from './components/Foo.vue'

const count = ref(0)
const increment = () => count.value++
const decrement = () => count.value--
</script>
  • defineProps 和 defineEmits 是编译器宏(compiler macros)

只能在 <script setup> 中使用。 它们不需要被导入,并且在处理 <script setup> 时被编译掉

  • 传递给 defineProps 和 defineEmits 的选项将被从 setup 中提升到模块范围

    因此,这些选项不能引用在 setup 作用域内声明的局部变量。这样做回导致一个编译错误。 然而,它可以引用导入的绑定,因为它们也在模块范围内

    export default {
      props: {
        foo: String
      },
      emits: ['change', 'delete'],
    
      // setup中定义的props和emits会被抽取到的模块作用域中
      setup(props, { emit }) {
          // setup code
      }
    }
    
  • props 和 emits 也可以使用 TypeScript 语法来声明,方法是向 defineProps 或 defineEmits 传递一个字面类型参数

const props = defineProps<{
  foo: string,
  bar?: number
}>()

const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
  • 使用 ts 语法来声明 props 和 emits, 没有办法为 props 提供默认值

为了解决这个问题,提供了一个 withDefaults 编译器宏(compiler macros)

interface Props {
  msg?: string
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello'
})

slots 和 attrs

<script setup> 中使用slots 和 attrs 应该是比较少的

如果你确实需要它们,请分别使用 useSlots 和 useAttrs 帮助函数 (helpers)

useSlots 和 useAttrs 是实际的运行时函数,其返回值等价于 setupContext.slots 和 setupContext.attrs 它们也可以在 Composition API 函数中使用

<script setup>
  import { useSlots, useAttrs } from 'vue'

  const slots = useSlots()
  const attrs = useAttrs()
</script>

顶层 await

顶层的 await 可以直接在 <script setup> 里面使用。由此产生的 setup() 函数 将自动添加 async

<script setup>
  const post = await fetch('/api/post/111').then(res => res.json())
</script>

与普通 script 一起使用

<script setup> 语法提供了表达大多数现有 Options API 选项同等功能的能力,只有少数选项除外。

  • name
  • inheritAttrs
  • 模块导出

如果你需要声明这些选项,请使用单独的普通 <script> 块,并使用导出默认值。

<script>
export default {
  name: 'CustomName',
  inheritAttrs: false,
}
</script>

<!-- <script setup>
// script setup logic
</script> -->