So far, setup Sugar has been finalized. Vue3 + Setup sugar + TS looks very nice. As of this writing, the Vue version is “^3.2.6”.
Script Setup syntax sugar
The new setup option, which is executed after props is resolved before the component is created, is an entry point to the composite API.
WARNING You should avoid using this in setup because it won’t find the component instance. Setup calls occur before data Property, computed Property, or methods are resolved, so they cannot > be retrieved in SETUP.
The setup option is a function that accepts the props and context, which we’ll discuss later. In addition, we expose everything that Setup returns to the rest of the component (computed properties, methods, lifecycle hooks, and so on) as well as the component’s template.
It is a new syntax sugar for Vue3, in the setup function. All ES module exports are considered context-exposed values and are included in the Setup () return object. The syntax is also simpler than before.
In a script tag with setup, we don’t need declarations and methods. This will automatically expose all top-level variables, functions, to the template.
It is as simple as adding the setup keyword to the script tag. Example:
<script setup></script>
Copy the code
This setup feature is a new component option. It is a unified API that exposes all properties and methods inside a component.
When used, this means that the contents of the script tag are equivalent to the function body of setup() in the original component declaration, though there are some differences.
With script Setup syntax sugar, components need to be imported without registration, properties and methods need not be returned, setup functions need not be written, export default need not be written, and even custom instructions can be obtained automatically in our template. The basic grammar
Call time
Create the component instance, initialize props, and then call the setup function. From a lifecycle hook perspective, it is called before the beforeCreate hook.
Use in templates
If Setup returns an object, the properties of the object will be incorporated into the rendering context of the component template
<template>
<div>
{{ count }} {{ object.foo }}
</div>
</template>
Copy the code
The setup parameters
- The first parameter of “props” takes a responsive props, which refers to external props. If you do not define the props option, the first parameter in setup will be undiam. Props is no different than vue2. X, still following the same principles;
- Do not modify props in child components; If you try to modify it, you will be given a warning or even an error.
- Don’t structure props. The props of the structure will become unresponsive.
2. The second argument to “context” provides a context object, which selectively exposes properties from the original 2.x.
<script setup="props, context" lang="ts">Copy the code
Like this, it is automatically imported by simply declaring it in setup, and also supports destruct syntax:
<script setup="props, { emit }" lang="ts">Copy the code
Automatic component registration
Import Component or directive without additional declaration
import { MyButton } from "@/components"
import { directive as clickOutside } from 'v-click-outside'
Copy the code
As before, the template also supports creating components using kabab-case, such as
In Script Setup, imported components can be used directly without having to register with components, and there is no way to specify the name of the current component, which automatically takes precedence over the file name, i.e. no need to write the name attribute. Example:
<template>
<HelloWorld />
</template>
<script setup>
import HelloWorld from "./components/HelloWorld.vue"; // Using the Vetur plugin here is red
</script>
Copy the code
If you want to define a property like name, you can add a horizontal script tag to it.
Use of component core apis
Define the props of the component
DefineProps specifies the current props type to get the props object of the context. Example:
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
title: String,})</script>
<!-- 或者 -->
<script setup lang="ts">
import { ref,defineProps } from 'vue';
type Props={
msg:string
}
defineProps<Props>();
</script>
Copy the code
Define emit
Use defineEmit to define the events contained by the current component and execute the emit through the returned context. Example:
<script setup>
import { defineEmits } from 'vue'
const emit = defineEmits(['change'.'delete'])
</script>
Copy the code
Parent-child component communication
DefineProps Props for receiving the parent component; defineEmits is used to declare triggered events.
/ / the parent component<template>
<my-son foo="🚀 🚀 🚀 🚀 🚀 🚀" @childClick="childClick" />
</template>
<script lang="ts" setup>
import MySon from "./MySon.vue";
let childClick = (e: any):void= > {
console.log('the from son:',e); / / 🚀 🚀 🚀 🚀 🚀 🚀
};
</script>/ / child component<template>
<span @click="sonToFather">Message :{{props. Foo}}</span>
</template>
<script lang="ts" setup>
import { defineEmits, defineProps} from "vue";
const emit = defineEmits(["childClick"]); // Declare the trigger event childClick
const props = defineProps({ foo: String }); / / get props
const sonToFather = () = >{
emit('childClick' , props.foo)
}
</script>
Copy the code
The child component receives data from the parent through defineProps, and the child component sends information to the parent through defineEmits defined events
The enhanced props type definition:
const props = defineProps<{
foo: string bar? : number }>()const emit = defineEmit<(e: 'update' | 'delete', id: number) = > void> ()Copy the code
Note, however, that this approach will not allow the props default to be used.
Define response variables, functions, listeners, and computed properties, computed
<script setup lang="ts">
import { ref,computed,watchEffect } from 'vue';
const count = ref(0); // Use templete directly without return
const addCount=() = >{ // Define a function, use the same method as above
count.value++;
}
// Define compute attributes, as above
const howCount=computed(() = >"Now count is:"+count.value);
// Define listener, use same as above //... some code else
watchEffect(() = >console.log(count.value));
</script>
Copy the code
watchEffect
For operations that have side effects, dependencies are automatically collected.
And watch the difference between
There is no need to distinguish between deep and immediate, which are called whenever the dependent data changes
reactive
If you want to change the value of name, you need to use Reactive in the Composition API.
<script setup lang="ts">
import { reactive, onUnmounted } from 'vue'
const state = reactive({
counter: 0
})
// The timer updates data every second
const timer = setInterval(() = > {
state.counter++
}, 1000);
onUnmounted(() = > {
clearInterval(timer);
})
</script>
<template>
<div>{{state.counter}}</div>
</template>
Copy the code
Using ref also achieves the desired ‘counter’, and in the template,vue handles it so that we can use counter directly instead of writing counter. Value.
Ref and Reactive:
Ref is a {value:’ XXXX ‘} structure, and value is a reactive object
Ref exposes variables to templates
In previous proposals, if you wanted to expose a variable to a template, you would add the export declaration before the variable:
export const count = ref(0)
Copy the code
In the new version of the proposal, however, the export declaration is not required; the compiler automatically looks for the variable used in the template, and a simple declaration like this is enough to use the variable in the template
<script setup lang="ts">
import { ref } from 'vue'
const counter = ref(0);// Use templete directly without return
const timer = setInterval(() = > {
counter.value++
}, 1000)
onUnmounted(() = > {
clearInterval(timer);
})
</script>
<template>
<div>{{counter}}</div>
</template>
Copy the code
Lifecycle approach
Because setup runs around beforeCreate and Created lifecycle hooks, there is no need to explicitly define them. In other words, any code written in these hooks should be written directly in the Setup function.
You can access a component’s lifecycle hook by prefixing it with “on”. Official website: Lifecycle hooks
The following table contains how to invoke lifecycle hooks within setup () :
Option type API | Hook inside setup |
---|---|
beforeCreate |
Not needed* |
created |
Not needed* |
beforeMount |
onBeforeMount |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeUnmount |
onBeforeUnmount |
unmounted |
onUnmounted |
errorCaptured |
onErrorCaptured |
renderTracked |
onRenderTracked |
renderTriggered |
onRenderTriggered |
activated |
onActivated |
deactivated |
onDeactivated |
<script setup lang="ts">
import { onMounted } from 'vue';
onMounted(() = > { console.log('mounted! '); });
</script>
Copy the code
Get slots and attrs
Note: The useContext API has been deprecated in favor of a more detailed API.
Slots and attrs can be obtained from the context via useContext. However, when the proposal was passed, it did away with this syntax and was split into useAttrs and useSlots.
useAttrs
This is used to get attrs data, but unlike vue2, it contains attrs dataclass
,attribute
,methods
.
<template>
<component v-bind='attrs'></component>
</template>
<srcipt setup lang='ts'>
const attrs = useAttrs();
<script>
Copy the code
useSlots
: As the name implies, gets slot data.
Example:
/ / the old<script setup>
import { useContext } from 'vue'
const { slots, attrs } = useContext()
</script>/ / new<script setup>
import { useAttrs, useSlots } from 'vue'
const attrs = useAttrs()
const slots = useSlots()
</script>
Copy the code
Other Hook Api
useCSSModule
: CSS Modules is a modular and combined system of CSS. Vue-loader integrates CSS Modules that can be used as simulated Scoped CSS. Allows components in a single filesetup
To access the CSS module. I use this API relatively little, but more introduction.useCssVars
: There is little information about this API. introducev-bind in styles
“Was mentioned.useTransitionState
: There is little information about this API.useSSRContext
: There is little information about this API.
defineExpose API
Traditionally, we can access the contents of the child components in the parent component through the ref instance, but in Script Setup, this method does not work. Setup is a closure, and no one can access the internal data and methods except the internal template template.
If you need to expose data and methods in setup, you need to use the defineExpose API. Example:
const a = 1
const b = ref(2)
defineExpose({ a, b, })
Copy the code
Note: The attributes and methods that are exposed by defineExpose are currently of unknown type. If you have a method to correct the type, please add it in the comments section.
/ / the parent component<template>
<Daughter ref="daughter" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
import Daughter from "./Daughter.vue";
const daughter = ref(null)
console.log('🚀 🚀 🚀 🚀 ~ daughter',daughter)
</script>/ / child component<template>
<div>Concubine {{MSG}}</div>
</template>
<script lang="ts" setup>
import { ref ,defineExpose} from "vue";
const msg = ref('the sable cicada')
defineExpose({
msg
})
</script>
Copy the code
Properties and methods do not need to be returned.
This is probably one of the big advantages of writing data and methods that need to be returned at the end before they can be used in the template. In Script Setup, properties and methods defined do not need to be returned and can be used directly! Example:
<template>
<div>
<p>My name is {{name}}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const name = ref('Sam')
</script>
Copy the code
Support async await async
Note that in the vue3 source code, a value inside getCurrentInstance releases a reference to currentInstance after setup is executed, and the await statement causes subsequent code to execute asynchronously. So the last getCurrentInstance() in the above example will return NULL, and it is recommended to use a variable to hold the reference returned by the first getCurrentInstance().
<script setup>
const post = await fetch(`/api/post/1`).then((r) = > r.json())
</script>
Copy the code
Top-level await can be used in
<script setup>
const post = await fetch(`/api/post/1`).then(r= > r.json())
</script>
Copy the code
In addition, the expression of await is automatically compiled in a format that preserves the context of the current component instance after await.
Note that Async Setup () must be combined with Suspense, which is currently an experimental feature. We plan to develop and document it in a future release – if you’re interested now, you can refer to tests to see how it works.
Define additional configuration of the component
Missing configuration items, sometimes we need to change component options, which we can’t currently do in Setup. We need to introduce another script at the top and write the corresponding export at the top. We need to open a single script.
- Can’t in
<script setup>
Declared options, for exampleinheritAttrs
Or custom options enabled by plug-ins. - Declare named exports.
- Run side effects or create objects that only need to be executed once.
Use Export Default outside of Script Setup and its contents are processed into the original component declaration field.
<script>
// Plain '
runSideEffectOnce()
// Declare additional options
export default {
name: "MyComponent".inheritAttrs: false.customOptions: {}}</script>
<script setup>
import HelloWorld from '.. /components/HelloWorld.vue'
// execute in the setup() scope (for each instance)
// your code
</script>
<template>
<div>
<HelloWorld msg="Vue3 + TypeScript + Vite"/>
</div>
</template>
Copy the code
Note: THE Vue 3 SFC will generally automatically infer the name of the component from its filename. In most cases, an explicit name declaration is not required. The only time you need this name is when you need
options to include or exclude or directly examine the component.
Imperfections with TS and ESLint
-
This rule is not compatible with @typescript-eslint/no-unused-vars. The meaning of this rule is defined and is not used. This rule has little effect, just turn it off.
-
Incompatible with imported type declarations, setup Sugar automatically exports the type when you destruct it. You will receive an error from TS saying that this is a type, but is being used as a value. Solution: Use export default to export or import data using import * as xx. You can also import type {test} from “./test”. To solve.
Syntactic sugar implementation
Vue file code
<template>
<div>{{ msg }}</div>
</template>
<script setup>
const msg = 'Hello! '
</script>
Copy the code
Compiled JS code:
export default {
setup() {
const msg = 'Hello! '
return function render() {
// has access to everything inside setup() scope
// In the function setup scope, render has access to everything in setup,
return h('div', msg)
}
}
}
Copy the code
Note that even ordinary variables can be put into a template and compiled as templates, which some people think is inappropriate and not separate enough.
Vscode plug-in
Volar is a vscode plug-in designed to enhance the vue writing experience. Use volar to get the best support for script setup syntax.
Like vetur, volar is a vscode plug-in for vue, but unlike vetur, volar offers much more powerful functionality that makes people say oh my god.
To install it, simply search for volar in vscode’s plugin marketplace and click install.
To use in vscode, disable Vetur before downloading and using Volar
Use habits
The biggest problem with switching from the Options API to the Composition API is that there is no mandatory code partition. If the writer does not have good code habits, it will be very difficult for subsequent writers. Here’s how I’ve solved it so far:
-
Self code partition and extract method as far as possible (write comment), partition as follows:
- Related introduction
- Reactive data, props, EMIT definitions
- Life cycle and watch writing
- Method definition
- Methods, attributes exposed
-
Component separation: Split the page into two folders, one for views and one for Components. The views and Components folders have their own files. The views folder contains the entry to the page and holds the data, while components separate the components from the page. If it is a public component, move it to another location in the Components folder.
-
Hook extraction: Remove logic as far as possible, not necessarily for reuse.
Write in the last
Writing is not easy, I hope I can get a “like” from you. If the article is useful to you, you can choose “follow + favorites”. If there are any mistakes or suggestions, please comment and correct them. Thank you. ❤ ️