1. Introduction
This article focuses on the basics of < Script Setup > and TypeScript.
What is
< Script Setup > is a compile-time syntactic sugar for using composition API in single-file components (SFC).
At the time of this writing, vUE is using version 3.2.26.
1.1. Development history
Let’s look at the evolution of vue3
Vue3
In earlier versions (3.0.0 - beta. 21
Before)composition api
Support is available only in component optionssetup
Function.
<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 {count, add,}}, }) </script>Copy the code
<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>
<template>
<h1>{{ msg }}</h1>
<button type="button" @click="add">count is: {{ count }}</button>
<ComponentA />
<ComponentB />
</template>
Copy the code
Advantage of 1.2.
Advantages of
- Less, cleaner code, no need to use
return {}
Exposed variables and methods, no active registration is required when using components; - better
Typescript
Support, use pureTypescript
The statementprops
And throw events are no longer like thatoption api
Is so lame; - Better runtime performance;
Of course, < Script Setup > has its drawbacks, such as the need to learn additional apis.
How to use
2. Use bullet points
2.1. Tools
Vue3 single file component (SFC) TS IDE support please use
Run the vue-tsc command to check the type.
- VSCode: The front end is best
IDE
. - Volar: in order to
Vue3
的*.vue
Single-file components provide support for code highlighting, syntax hints, and moreVSCode
Plug-in;Vue2
You may be usingVetur
Plugins need to be disabledVetur
Download,Volar
And enable it. - vue-tsc: Type check and
dts
Build command line tools.
2.2. Basic Usage
Add the setup property to the
<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>
Copy the code
To use TypeScript, add the lang attribute to the
<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>
Copy the code
The script in the
Top-level bindings declared in < Script Setup > (variables, functions, imported content) are automatically exposed to the template and used directly in the template.
<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>
Copy the code
Note:
-
Each *.vue file can contain up to one
-
Each *.vue file can contain up to one
2.3. Compiler macros
** Compiler macros ** include: defineProps, defineEmits, withDefaults, defineExpose, etc.
Compiler macros can only be used in < Script Setup > blocks, do not need to be imported, and are compiled away when processing < Script Setup > blocks.
Compiler macros must be used at the top level of < Script Setup > and may not be referenced in local variables of < Script Setup >.
defineProps
There are no component configuration items in the
<script setup> const props = defineProps({MSG: String, title: {type: String, default: 'I'm the title'}, list: {type: Array, default: () => []}}) // Use the properties console.log(props. MSG) </script> <template> <! - a variable declared in a direct use of props in the template - > < h1 > {{MSG}} < / h1 > < div > {{title}} < / div > < / template >Copy the code
TS version:
<script setup lang="ts"> interface ListItem { name: string age: number } const props = defineProps<{ msg: string title: string list: ListItem[]}>() // use properties in props in ts, Console. log(props. List [0].age) </script> <template> <h1>{{MSG}}</h1> <div>{{title}}</div> </template>Copy the code
In this code, we can see that props does not define a default value.
Vue3 provides us with the withDefaults compiler macro, which provides default values for props.
<script setup lang="ts"> interface ListItem {name: string age: number} interface Props {MSG: string // title : string list: ListItem[]} // the second argument to withDefaults is the default argument setting, Const props = withDefaults(defineProps< props >(), {title: 'I am the title ', // For array and object we need to use the function list as before: () => []}) // Use properties in props in ts, Console. log(props. List [0].age) </script> <template> <h1>{{MSG}}</h1> <div>{{title}}</div> </template>Copy the code
One caveat: declaring a variable at the top level with the same name as the props property is a bit of a problem.
<script setup> const props = defineProps({ title: { type: String, default: Const title = '123' </script> <template> <! <div>{{props. Title}}</div> <! <div>{{title}}</div> </template>Copy the code
So, as with component options, do not define a top-level variable with the same name as the properties of props.
defineEmits
Similarly, there is no component configuration item emits in the
// ./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>
Copy the code
Using components:
<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>
Copy the code
TS version:
// ./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>
Copy the code
Using components:
<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>
Copy the code
defineExpose
In Vue3, any bindings declared in < Script Setup > are not exposed by default, that is, bindings declared by component instances cannot be retrieved from the template ref.
Vue3 provides the defineExpose compiler macro, which explicitly exposes variables and methods declared in the component that you want to expose.
// ./components/HelloWorld.vue <script setup> import { ref } from 'vue' const msg = ref('Hello Vue3') const HandleChangeMsg = (v) => {msg.value = v} // Expose({MSG, handleChangeMsg, }) </script> <template> <h1>{{ msg }}</h1> </template>Copy the code
Using components:
<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>
Copy the code
TS version:
// ./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>
Copy the code
Using components:
<script setup lang="ts"> import { ref, OnMounted} from 'vue' import HelloWorld from '. / components/HelloWorld. Vue '/ / temporarily use any here, 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>Copy the code
2.4. Auxiliary functions
UseAttrs, useSlots, useCssModule. The other functions are still in the experimental stage.
useAttrs
Use $attrs in the template to access attrs data. Compared to Vue2, Vue3’s $attrs also contains class and style attributes.
Use the useAttrs function in
<script setup> import HelloWorld from './components/HelloWorld.vue' </script> <template> <HelloWorld class="hello-word" /> </template>Copy the code
/ /. / components/HelloWorld. Vue < script setup > import {useAttrs} from 'vue' const attrs = useAttrs () / / js Console. log(attrs.class) // hello-word console.log(attrs.title) // I am the title </script> <template> <! <div>{{$attrs. Title}}</div> </template>Copy the code
useSlots
Use $slots in the template to access the slots data.
Get the slots data using the useSlots function in
< script setup > import HelloWorld from '. / components/HelloWorld. Vue '< / script > < template > < the HelloWorld > < div > default slot < / div > <template v-slot:footer> <div> Named slot footer</div> </template> </HelloWorld> </template>Copy the code
<script setup> import {useSlots} from 'vue' const slots = useSlots( console.log(slots.default) console.log(slots.footer) </script> <template> <div> <! - the use of a slot in the template - > < slot > < / slot > < slot name = "footer" > < / slot > < / div > < / template >Copy the code
useCssModule
In Vue3, CSS Modules are also supported. Add the module attribute to
The
<script setup lang="ts"> import {useCssModule} from 'vue' Const style = useCssModule() console.log(style.success) // The success class name has been hash calculated Pass the parameter Content, <style module="content"> const contentStyle = useCssModule('content') </script> <template> <div Class ="success"> Normal style red</div> <div :class="$style.success"> Default CssModule pink</div> <div :class="style.success"> Default CssModule pink</div> <div :class=" contentstyle. success"> Named CssModule blue</div> <div :class="content.success"> named CssModule blue</div> </template> <! <style>. Success {color: red; } </style> <! <style module lang="less">. Success {color: pink; } </style> <! <style module="content" lang="less">. Success {color: blue; } </style>Copy the code
Note that the CSS Module with the same name overwrites the previous one.
2.5. Use components
In the Component option, the template needs to use components (except global components) and needs to be registered in the Components option.
In < Script Setup >, components do not need to be registered, and templates can be used directly, which is essentially a top-level variable.
It is recommended to use PascalCase to name and use components.
<script setup>
import HelloWorld from './HelloWorld.vue'
</script>
<template>
<HelloWorld />
</template>
Copy the code
2.6. The component 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>
Copy the code
Use:
<script setup>
import HelloWorld from './components/HelloWorld.vue'
console.log(HelloWorld.name) // 'HelloWorld'
</script>
<template>
<HelloWorld />
</template>
Copy the code
Note: If you set the lang property,
2.7. inheritAttrs
InheritAttrs indicates whether attribute inheritance is disabled. The default value is true.
< script setup > import HelloWorld from '. / components/HelloWorld. Vue '< / script > < template > < the HelloWorld title = "I am the title" / > </template>Copy the code
./components/HelloWorld.vue
<script> export default { name: 'HelloWorld', inheritAttrs: false, } </script> <script setup> import { useAttrs } from 'vue' const attrs = useAttrs() </script> <template> <div> <span <span :title="$attrs.title">hover </span> </span>Copy the code
2.8. Top-level await support
Top-level await can be used in
<script setup>
const userInfo = await fetch(`/api/post/getUserInfo`)
</script>
Copy the code
Note: Async Setup () must be used in combination with Suspense. Suspense is an experimental feature and its API is subject to change at any time, so it is not recommended.
2.9. Namespace components
In VUE3, we can use point syntax to use components mounted on an object.
// components/Form/index.js
import Form from './Form.vue'
import Input from './Input.vue'
import Label from './Label.vue'
// Mount the Input and Label components to the Form component
Form.Input = Input
Form.Label = Label
export default Form
Copy the code
/ / use: <script setup lang="ts"> import Form from './components/Form' </script> <template> <Form> <Form.Label /> <Form.Input /> </Form> </template>Copy the code
The use of namespace components in another scenario, when importing multiple components from a single file:
// FormComponents/index.js
import Input from './Input.vue'
import Label from './Label.vue'
export default {
Input,
Label,
}
Copy the code
Import * as Form from './FormComponents' </script> <template> < form.input > <Form.Label>label</Form.Label> </Form.Input> </template>Copy the code
2.10. State-driven dynamic CSS
The
<script setup> const theme = { color: 'red'} </script> <template> <p>hello</p> </template> <style scoped> p {// Use the top binding color: v-bind('theme. } </style>Copy the code
2.11. Instructions
Global directive:
<template>
<div v-click-outside />
</template>
Copy the code
Custom instruction:
<script setup> import {ref} from 'vue' const total = ref(10) // Custom directives // Must be named in the format of a small hump beginning with a lowercase v // when used in templates, Do not use vMyDirective const vMyDirective = {beforeMount: 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>Copy the code
Import directives:
Import {directive as vClickOutside} from 'v-click-outside' </script> <template> <div v-click-outside /> </template>Copy the code
More about instructions, see the official document (v3.cn.vuejs.org/guide/custo…
2.12. Composition Api Type Constraints
<script setup lang="ts"> import { ref, reactive, computed } from 'vue' type User = { name: string age: Number} // const msg1 = ref('') // Const user1 = ref<User>({name: 'tang', age: Reactive ({}) const user2 = reactive({}) const user2 = reactive({}) const user2 = 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>Copy the code
3. Reference documents
- sfc-script-setup