Vue3 <script setup lang=“ts“> 的基本使用

目录
  • 1.<script setup> 是什么?
    • 1.1. 发展历程
    • 1.2. 优势
  • 2. 使用要点
    • 2.1. 工具
    • 2.2. 基本用法
    • 2.3. 编译器宏
    • 2.4. 辅助函数
    • 2.5. 使用组件
    • 2.6. 组件name
    • 2.7. inheritAttrs
    • 2.8. 顶层await支持
    • 2.9. 命名空间组件
    • 2.10. 状态驱动的动态 CSS
    • 2.11. 指令
    • 2.12. Composition Api类型约束

本文主要是讲解 <script setup> 与 TypeScript 的基本使用。

1.<script setup> 是什么?

<script setup> 是在单文件组件 (SFC) 中使用 composition api 的编译时语法糖。

本文写作时,vue 使用的 3.2.26 版本。

1.1. 发展历程

我们先看看 vue3 <script setup> 的发展历程:

Vue3 在早期版本( 3.0.0-beta.21 之前)中对 composition api 的支持,只能在组件选项 setup 函数中使用。

<template>

<h1>{{ msg }}</h1>

<button type="button" @click="add">count is: {{ count }}</button>

<ComponentA />

<ComponentB />

</template>

<script>

import { defineComponent, ref } from 'vue'

import ComponentA from '@/components/ComponentA'

import ComponentB from '@/components/ComponentB'

export default defineComponent({

name: 'HelloWorld',

components: { ComponentA, ComponentB },

props: {

msg: String,

},

setup(props, ctx) {

const count = ref(0)

function add() {

count.value++

}

// 使用return {} 把变量、方法暴露给模板

return {

count,

add,

}

},

})

</script>
  • 在 3.0.0-beta.21 版本中增加了 <script setup> 的实验特性。如果你使用了,会提示你 <script setup> 还处在实验特性阶段。
  • 在 3.2.0 版本中移除 <script setup> 的实验状态,从此,宣告 <script setup> 正式转正使用,成为框架稳定的特性之一。
<script setup lang="ts">

import { ref } from 'vue'

import ComponentA from '@/components/ComponentA'

import ComponentB from '@/components/ComponentB'

defineProps<{ msg: string }>()
const count = ref(0)
function add() {

count.value++

}

</script>x
<template>

<h1>{{ msg }}</h1>

<button type="button" @click="add">count is: {{ count }}</button>

<ComponentA />

<ComponentB />

</template>

1.2. 优势

与组件选项 setup 函数对比, <script setup> 的优点:

  • 更少、更简洁的代码,不需要使用 return {} 暴露变量和方法了,使用组件时不需要主动注册了;
  • 更好的 Typescript 支持,使用纯 Typescript 声明 props 和抛出事件,不会再像 option api 里那么蹩脚了;
  • 更好的运行时性能;

当然, <script setup> 也是有自己的缺点的,比如需要学习额外的 API

那么 <script setup> 怎么使用呢?有哪些使用要点?与TypeScript如何结合?

2. 使用要点

2.1. 工具

Vue3 单文件组件 (SFC) 的 TS IDE 支持请用 <script setup lang="ts"> + VSCode + Volar

类型检查使用 vue-tsc 命令。

VSCode:前端最好用的 IDE

Volar:为 Vue3 的 *.vue 单文件组件提供代码高亮、语法提示等功能支持的 VSCode 插件;Vue2 你可能是使用的 Vetur 插件,需要禁用 Vetur,下载 Volar,并启用它。

vue-tsc:类型检查和 dts 构建命令行工具。

2.2. 基本用法

将 setup 属性添加到 <script> 代码块上。

<script setup>

import { ref } from 'vue'

defineProps({

msg: String

})

const count = ref(0)

function add() {

count.value++

}

</script>

<template>

<h1>{{ msg }}</h1>

<button type="button" @click="add">count is: {{ count }}</button>

</template>

若需要使用 TypeScript,则将 lang 属性添加到 <script> 代码块上,并赋值 ts

<script setup lang="ts">

import { ref } from 'vue'

defineProps<{ msg: string }>()
const count = ref(0)

function add() {

count.value++

}

</script>

<template>

<h1>{{ msg }}</h1>

<button type="button" @click="add">count is: {{ count }}</button>

</template>

<script setup> 块中的脚本会被编译成组件选项 setup 函数的内容,也就是说它会在每次组件实例被创建的时候执行。

在 <script setup> 声明的顶层绑定(变量、函数、import引入的内容),都会自动暴露给模板,在模板中直接使用。

<script setup>

import { ref } from 'vue'

// 外部引入的方法,不需要通过 methods 选项来暴露它,模板可以直接使用

import { getToken } from './utils'

// 外部引入的组件,不需要通过 components 选项来暴露它,模板可以直接使用

import ComponentA from '@/components/ComponentA'

defineProps({

msg: String

})

// 变量声明,模板可以直接使用

const count = ref(0)

// 函数声明,模板可以直接使用

function add() {

count.value++

}

</script>
<template>

<h1>{{ msg }}</h1>

<h1>{{ getToken() }}</h1>

<button type="button" @click="add">count is: {{ count }}</button>

<ComponentA />

</template>

注意:

  • 每个 *.vue 文件最多可同时包含一个 <script> 块 (不包括<script setup>);
  • 每个 *.vue 文件最多可同时包含一个 <script setup> 块 (不包括常规的 <script>);

2.3. 编译器宏

编译器宏(compiler macros) 有:definePropsdefineEmitswithDefaultsdefineExpose 等。

编译器宏只能在 <script setup> 块中使用,不需要被导入,并且会在处理 <script setup> 块时被一同编译掉。

编译器宏必须在 <script setup> 的顶层使用,不可以在 <script setup> 的局部变量中引用。

defineProps

在 <script setup> 块中是没有组件配置项的,也就是说是没有 props 选项,需要使用 defineProps 来声明 props 相关信息。defineProps 接收的对象和组件选项 props 的值一样。

<script setup>

const props = defineProps({

msg: String,

title: {

type: String,

default: '我是标题'

},

list: {

type: Array,

default: () => []

}

})
// 在 js 中使用 props 中的属性

console.log(props.msg)

</script>
<template>

<!-- 在模板中直接使用 props 中声明的变量 -->

<h1>{{ msg }}</h1>

<div>{{ title }}</div>

</template>

TS 版本:

<script setup lang="ts">

interface ListItem {

name: string

age: number

}
const props = defineProps<{

msg: string

title: string

list: ListItem[]

}>()
// 在 ts 中使用 props 中的属性,具有很好的类型推断能力

console.log(props.list[0].age)

</script>
<template>

<h1>{{ msg }}</h1>

<div>{{ title }}</div>

</template>

从代码中可以发现 TS 写法里 props 没有定义默认值。

Vue3 为我们提供了 withDefaults 这个编译器宏,给 props 提供默认值。

<script setup lang="ts">

interface ListItem {

name: string

age: number

}

interface Props {

msg: string

// title可选

title?: string

list: ListItem[]

}

// withDefaults 的第二个参数便是默认参数设置,会被编译为运行时 props 的 default 选项

const props = withDefaults(defineProps<Props>(), {

title: '我是标题',

// 对于array、object需要使用函数,和以前的写法一样

list: () => []

})

// 在 ts 中使用 props 中的属性,具有很好的类型推断能力

console.log(props.list[0].age)

</script>
<template>

<h1>{{ msg }}</h1>

<div>{{ title }}</div>

</template>

一个需要注意的地方:在顶层声明一个和props的属性同名的变量,会有些问题。

<script setup>

const props = defineProps({

title: {

type: String,

default: '我是标题'

}

})

// 在顶层声明一个和props的属性title同名的变量

const title = '123'
</script>
<template>

<!-- props.title 显示的是 props.title 的值,‘我是标题' -->

<div>{{ props.title }}</div>

<!-- title 显示的是 在顶层声明的 title 的值,‘123' -->

<div>{{ title }}</div>

</template>

所以,和组件选项一样,不要定义和 props 的属性同名的顶层变量。

defineEmits

一样的,在 <script setup> 块中也是没有组件配置项 emits 的,需要使用 defineEmits 编译器宏声明 emits 相关信息。

// ./components/HelloWorld.vue

<script setup>

defineProps({

msg: String,

})
const emits = defineEmits(['changeMsg'])
const handleChangeMsg = () => {

emits('changeMsg', 'Hello TS')

}

</script>
<template>

<h1>{{ msg }}</h1>

<button @click="handleChangeMsg">handleChangeMsg</button>

</template>

使用组件:

<script setup>

import { ref } from 'vue'

import HelloWorld from './components/HelloWorld.vue'
const msg = ref('Hello Vue3')

const changeMsg = (v) => {

msg.value = v

}

</script>
<template>

<HelloWorld :msg="msg" @changeMsg="changeMsg" />

</template>

TS 版本:

// ./components/HelloWorld.vue

<script setup lang="ts">
defineProps<{

msg: string

}>()
const emits = defineEmits<{

(e: 'changeMsg', value: string): void

}>()
const handleChangeMsg = () => {

emits('changeMsg', 'Hello TS')

}

</script>
<template>

<h1>{{ msg }}</h1>

<button @click="handleChangeMsg">handleChangeMsg</button>

</template>

使用组件:

<script setup lang="ts">

import { ref } from 'vue'

import HelloWorld from './components/HelloWorld.vue'

const msg = ref('Hello Vue3')

const changeMsg = (v: string) => {

msg.value = v

}

</script>
<template>

<HelloWorld :msg="msg" @changeMsg="changeMsg" />

</template>

defineExpose

在 Vue3中,默认不会暴露任何在 <script setup> 中声明的绑定,即不能通过模板 ref 获取到组件实例声明的绑定。

Vue3 提供了 defineExpose 编译器宏,可以显式地暴露需要暴露的组件中声明的变量和方法。

// ./components/HelloWorld.vue

<script setup>

import { ref } from 'vue'

const msg = ref('Hello Vue3')
const handleChangeMsg = (v) => {

msg.value = v

}

// 对外暴露的属性

defineExpose({

msg,

handleChangeMsg,

})

</script>

使用组件:

<script setup>

import { ref, onMounted } from 'vue'

import HelloWorld from './components/HelloWorld.vue'
const root = ref(null)
onMounted(() => {

console.log(root.value.msg)

})
const handleChangeMsg = () => {

root.value.handleChangeMsg('Hello TS')

}

</script>
<template>

<HelloWorld ref="root" />

<button @click="handleChangeMsg">handleChangeMsg</button>

</template>

TS 版本:

// ./components/HelloWorld.vue

<script setup lang="ts">

import { ref } from 'vue'

const msg = ref('Hello Vue3')
const handleChangeMsg = (v: string) => {

msg.value = v

}
defineExpose({

msg,

handleChangeMsg

})

</script>
<template>

<h1>{{ msg }}</h1>

</template>

使用组件:

<script setup lang="ts">

import { ref, onMounted } from 'vue'

import HelloWorld from './components/HelloWorld.vue'

// 此处暂时使用any,需要定义类型

const root = ref<any>(null)
onMounted(() => {

console.log(root.value.msg)

})
const handleChangeMsg = () => {

root.value.handleChangeMsg('Hello TS')

}
</script>
<template>

<HelloWorld ref="root" />

<button @click="handleChangeMsg">handleChangeMsg</button>

</template>

2.4. 辅助函数

在 <script setup> 中常用的辅助函数hooks api,主要有:useAttrsuseSlotsuseCssModule,其他的辅助函数还在实验阶段,不做介绍。

useAttrs

在模板中使用 $attrs 来访问 attrs 数据,与 Vue2 相比,Vue3 的 $attrs 还包含了 class 和 style 属性。

在 <script setup> 中使用 useAttrs 函数获取 attrs 数据。

<script setup>

import HelloWorld from './components/HelloWorld.vue'

</script>
<template>
<HelloWorld class="hello-word" title="我是标题" />

</template>
// ./components/HelloWorld.vue

<script setup>

import { useAttrs } from 'vue'
const attrs = useAttrs()

// js中使用

console.log(attrs.class) // hello-word

console.log(attrs.title) // 我是标题

</script>
<template>

<!-- 在模板中使用 $attrs 访问属性 -->

<div>{{ $attrs.title }}</div>

</template>

useSlots

在模板中使用 $slots 来访问 slots 数据。

在 <script setup> 中使用 useSlots 函数获取 slots 插槽数据。

<script setup>

import HelloWorld from './components/HelloWorld.vue'

</script>
<template>

<HelloWorld>

<div>默认插槽</div>

<template v-slot:footer>

<div>具名插槽footer</div>

</template>

</HelloWorld>

</template>
<script setup>

import { useSlots } from 'vue'

const slots = useSlots()

// 在js中访问插槽默认插槽default、具名插槽footer

console.log(slots.default)

console.log(slots.footer)

</script>
<template>

<div>

<!-- 在模板中使用插槽 -->

<slot></slot>

<slot name="footer"></slot>

</div>

</template>

useCssModule

在 Vue3 中,也是支持 CSS Modules 的,在 <style> 上增加 module 属性,即<style module>

<style module> 代码块会被编译为 CSS Modules 并且将生成的 CSS 类作为 $style 对象的键暴露给组件,可以直接在模板中使用 $style。而对于如 <style module="content"> 具名 CSS Modules,编译后生成的 CSS 类作为 content 对象的键暴露给组件,即module 属性值什么,就暴露什么对象。

<script setup lang="ts">

import { useCssModule } from 'vue'

// 不传递参数,获取<style module>代码块编译后的css类对象

const style = useCssModule()

console.log(style.success) // 获取到的是success类名经过 hash 计算后的类名

// 传递参数content,获取<style module="content">代码块编译后的css类对象

const contentStyle = useCssModule('content')

</script>

<template>

<div class="success">普通style red</div>

<div :class="$style.success">默认CssModule pink</div>

<div :class="style.success">默认CssModule pink</div>

<div :class="contentStyle.success">具名CssModule blue</div>

<div :class="content.success">具名CssModule blue</div>

</template>

<!-- 普通style -->

<style>

.success {

color: red;

}

</style>
<!-- 无值的css module -->

<style module lang="less">

.success {

color: pink;

}

</style>
<!-- 具名的css module -->

<style module="content" lang="less">

.success {

color: blue;

}

</style>

注意,同名的CSS Module,后面的会覆盖前面的。

2.5. 使用组件

在组件选项中,模板需要使用组件(除了全局组件),需要在 components 选项中注册。

而在 <script setup> 中组件不需要再注册,模板可以直接使用,其实就是相当于一个顶层变量。

建议使用大驼峰(PascalCase)命名组件和使用组件。

<script setup>

import HelloWorld from './HelloWorld.vue'

</script>
<template>

<HelloWorld />

</template>

2.6. 组件name

<script setup> 是没有组件配置项 name 的,可以再使用一个普通的 <script> 来配置 name

// ./components/HelloWorld.vue

<script>

export default {

name: 'HelloWorld'

}

</script>
<script setup>

import { ref } from 'vue'

const total = ref(10)

</script>
<template>

<div>{{ total }}</div>

</template>

使用:

<script setup>

import HelloWorld from './components/HelloWorld.vue'

console.log(HelloWorld.name) // 'HelloWorld'

</script>
<template>

<HelloWorld />

</template>

注意: 如果你设置了 lang 属性,<script setup> 和 <script> 的 lang 需要保持一致。

2.7. inheritAttrs

inheritAttrs 表示是否禁用属性继承,默认值是 true

<script setup> 是没有组件配置项 inheritAttrs 的,可以再使用一个普通的 <script>

<script setup>

import HelloWorld from './components/HelloWorld.vue'

</script>
<template>

<HelloWorld title="我是title"/>

</template>

./components/HelloWorld.vue

<script>

export default {

name: 'HelloWorld',

inheritAttrs: false,

}

</script>
<script setup>

import { useAttrs } from 'vue'

const attrs = useAttrs()

</script>
<template>

<div>

<span :title="attrs.title">hover一下看title</span>

<span :title="$attrs.title">hover一下看title</span>

</div>

</template>

2.8. 顶层await支持

<script setup> 中可以使用顶层 await。结果代码会被编译成 async setup()

<script setup>

const userInfo = await fetch(`/api/post/getUserInfo`)

</script>

注意:async setup() 必须与 Suspense 组合使用,Suspense 目前还是处于实验阶段的特性,其 API 可能随时会发生变动,建议暂时不要使用。

2.9. 命名空间组件

在 vue3 中,我们可以使用点语法来使用挂载在一个对象上的组件。

// components/Form/index.js

import Form from './Form.vue'

import Input from './Input.vue'

import Label from './Label.vue'

// 把Input、Label组件挂载到 Form 组件上

Form.Input = Input

Form.Label = Label
export default Form
// 使用:

<script setup lang="ts">

import Form from './components/Form'

</script>
<template>

<Form>

<Form.Label />

<Form.Input />

</Form>

</template>

命名空间组件在另外一种场景中的使用,从单个文件中导入多个组件时:

// FormComponents/index.js

import Input from './Input.vue'

import Label from './Label.vue'
export default {

Input,

Label,

}
// 使用

<script setup>

import * as Form from './FormComponents'

</script>
<template>

<Form.Input>

<Form.Label>label</Form.Label>

</Form.Input>

</template>

2.10. 状态驱动的动态 CSS

Vue3 中 <style> 标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上。

<script setup>

const theme = {

color: 'red'

}

</script>
<template>

<p>hello</p>

</template>
<style scoped>

p {

// 使用顶层绑定

color: v-bind('theme.color');

}

</style>

2.11. 指令

全局指令:

<template>
<div v-click-outside />
</template>

自定义指令:

<script setup>

import { ref } from 'vue'

const total = ref(10)

// 自定义指令

// 必须以 小写字母v开头的小驼峰 的格式来命名本地自定义指令

// 在模板中使用时,需要用中划线的格式表示,不可直接使用vMyDirective

const vMyDirective = {

beforeMount: (el, binding, vnode) => {

el.style.borderColor = 'red'

},

updated(el, binding, vnode) {

if (el.value % 2 !== 0) {

el.style.borderColor = 'blue'

} else {

el.style.borderColor = 'red'

}

},

}
const add = () => {

total.value++

}

</script>
<template>

<input :value="total" v-my-directive />

<button @click="add">add+1</button>

</template>

导入的指令:

<script setup>

// 导入的指令同样需要满足命名规范

import { directive as vClickOutside } from 'v-click-outside'

</script>
<template>

<div v-click-outside />

</template>

更多关于指令,见官方文档(https://v3.cn.vuejs.org/guide/custom-directive.html#%E7%AE%80%E4%BB%8B、https://v3.cn.vuejs.org/api/application-api.html#directive)。

2.12. Composition Api类型约束

<script setup lang="ts">
import { ref, reactive, computed } from 'vue'

type User = {
  name: string
  age: number
}

// ref
const msg1 = ref('')  //  会默认约束成 string 类型,因为ts类型推导
const msg2 = ref<string>('')  //  可以通过范型约束类型
const user1 = ref<User>({ name: 'tang', age: 18 })  //  范型约束
const user2 = ref({} as User)  // 类型断言

// reactive
const obj = reactive({})
const user3 = reactive<User>({ name: 'tang', age: 18 })
const user4 = reactive({} as User)

// computed
const msg3 = computed(() => msg1.value)
const user5 = computed<User>(() => {
  return { name: 'tang', age: 18 }
})
</script>

到此这篇关于Vue3 <script setup lang=“ts“> 使用指南的文章就介绍到这了,更多相关Vue3 <script setup lang=“ts“>内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Vue3 父组件调用子组件方法($refs 在setup()、<script setup> 中使用)

    在 vue2 中 ref 被用来获取对应的子元素,然后调用子元素内部的方法. <template> <!-- 子组件 --> <TestComponent ref="TestComponent"></TestComponent> </template> <script> // 导入子组件 import TestComponent from './TestComponent' export default { com

  • 详解如何在Vue3使用<script lang=“ts“ setup>语法糖

    目录 迁移组件 隐式返回 defineProps defineEmits 默认关闭和defineExpose Vue 3.2 引入了语法,这是一种稍微不那么冗长的声明组件的方式.您可以通过向 SFC 的元素添加属性来启用它,然后可以删除组件中的一些样板.script setupsetupscript 让我们举一个实际的例子,并将其迁移到这个语法! 迁移组件 以下组件有两个道具(要显示的和一个标志).基于这两个道具,计算模板中显示的小马图像的URL(通过另一个组件).该组件还会在用户单击它时发出一

  • Vue3 <script setup lang=“ts“> 的基本使用

    目录 1.<script setup> 是什么? 1.1. 发展历程 1.2. 优势 2. 使用要点 2.1. 工具 2.2. 基本用法 2.3. 编译器宏 2.4. 辅助函数 2.5. 使用组件 2.6. 组件name 2.7. inheritAttrs 2.8. 顶层await支持 2.9. 命名空间组件 2.10. 状态驱动的动态 CSS 2.11. 指令 2.12. Composition Api类型约束 本文主要是讲解 <script setup> 与 TypeScrip

  • Vue3+script setup+ts+Vite+Volar搭建项目

    目录 使用 Vite 创建 vue + ts 项目 Vue 3 的三种语法 Option API Composition API script setup(Composition API 的语法糖) 安装 Volar 结尾 好久没有写了,最近看到Vue3.2 发布了,害,又要开始卷了么. 其实我自己本身还没有使用过Vue3 做过实际的项目开发,然鹅又出新东西了--, 新时代农民工真的是左手工作,右手游戏,还要用jio去学习呢. 什么? 你说谈对象? xswl,我特么一个农民工也配谈对象? 不卷不

  • vue3基于script setup语法$refs的使用

    目录 一.vue2语法 二.vue3使用 1. 组件设置ref值 2. 组件实例获取 3. 子组件内设置对外公开的变量 一.vue2语法 vue2语法在组件上设置ref属性后,在代码里可以通过 this.$refs.ref值 访问到对应的子组件. 一个设置ref值的组件: <base-input ref="usernameInput"></base-input> 在js代码中可以通过如下代码访问到这个组件: this.$refs.usernameInput 可以

  • vue3基于script setup语法$refs的使用

    目录 一.vue2语法 二.vue3使用 1. 组件设置ref值 2. 组件实例获取 3. 子组件内设置对外公开的变量 一.vue2语法 vue2语法在组件上设置ref属性后,在代码里可以通过 this.$refs.ref值 访问到对应的子组件. 一个设置ref值的组件: <base-input ref="usernameInput"></base-input> 在js代码中可以通过如下代码访问到这个组件: this.$refs.usernameInput 可以

  • vue3项目中引入ts的详细图文教程

    目录 1.基于脚手架的情况下创建 vue3项目 2.启动未引入ts的vue3项目 3.在页面中(HomeView.vue)引入ts 4.配置vue3+ts项目 5.其他配置 6.在HomeView.vue 使用Ts语法 总结 提示:文章是基于vue3的项目基础上引入ts 1.基于脚手架的情况下创建 vue3项目 vue create vue3-ts 选择自定义预设,ts设置未选中状态 选择yarn与npm启动项目(根据个人,在这里我选择yarn) 2.启动未引入ts的vue3项目 3.在页面中(

  • vue3中setup语法糖下通用的分页插件实例详解

    目录 vue3中setup语法糖下父子组件之间的通信 准备工作 父传子: 子传父: 先给大家介绍下vue3中setup语法糖下通用的分页插件,内容如下所示: 效果 自定义分页插件:PagePlugin.vue <script setup lang="ts"> // total :用来传递数据总条数 // pageSize :每页展示几条数据 // currentPage :当前默认页码 // change-page :页码改变时触发的事件,参数为当前页码 const pro

  • vue3中单文件组件<script setup>实例详解

    目录 一.相比普通script语法的优势 二.基本语法 三.响应式 四.使用组件 五.使用自定义指令 六.defineProps 和 defineEmits 七.defineExpose 八.useSlots 和 useAttrs 九.顶层 await 附:<script setup>和 <script>之间的主要区别 总结 一.相比普通script语法的优势 <script setup>是在单文件组件 (SFC) 中使用组合式 API的编译时语法糖.相比于普通的 &l

  • Vue3中SetUp函数的参数props、context详解

    1.setUp函数的第1个参数props setup(props,context){} 第一个参数props: props是一个对象,包含父组件传递给子组件的所有数据. 在子组件中使用props进行接收. 包含配置声明并传入的所有的属性的对象 也就是说:如果你想通过props的方式输出父组件传递给子组件的值. 你需要使用props进行接收配置.即props:{......} 如果你未通过Props进行接受配置,则输出的值是undefined <template> <div class=&

随机推荐