Modular API
Any API that needs to be used requires import, which is automatically completed by the plug-in
import { defineProps, reactive, computed, onMounted, onUnmounted, ref, toRefs, watch } from 'vue'
Copy the code
Responsiveness API
1 Basic API for responsiveness
reactive
Returns a responsive copy of the object, packaging all the properties and methods into a single object
Instead, they are aggregated into an object so that the properties within the data object can respond to external changes
const data = reactive({
counter: 1.doubleCounter: computed(() = > data.counter * 2)})let timer;
onMounted(() = > {
timer = setInterval(() = > {
data.counter++
}, 1000);
})
onUnmounted(() = > {
clearInterval(timer);
})
return toRefs(data);
Copy the code
The internal properties are read through data.counter and data.doublecountert, allowing the internal data to respond to changes in the external methods
Package combination function
To make the code more organized, we can package the composite function as a function, return the property, and call the function by declaring the name of the function to get the object
const data = useCounter();
function useCounter(() = > {const data = reactive({
counter: 1,
doubleCounter: computed(() => data.counter * 2)})let timer;
onMounted(()=> {
timer = setInterval(() => {
data.counter++
}, 1000);
})
onUnmounted(()=> {
clearInterval(timer);
})
return data;
})
Copy the code
Compared with Vue2, data, computed, and watch are broken down, which prevents the previous operation from repeatedly jumping between these apis
2 Refs
ref
Take a single value and return a responsive and variable ref object with a single property.value pointing inward
const count = ref(0)
console.log(count.value) / / 0
count.value++
console.log(count.value) / / 1
Copy the code
If you need to allocate an object to a ref value, you need to make the object highly reactive by using the reactive method
unref()
Returns the internal value if the argument is a ref, otherwise returns the value of the argument itself, which is val = isRef(val)? Val.value: The syntactic sugar function for val
function useFoo (x: number | Ref<number>) {
const unwrapped = unref(x) // It must be numeric now
}
Copy the code
toRef()
Can be used to create a new ref for an attribute of the source responsive object, and then the REF can be passed, keeping the responsive link to its source attribute
const state = reactive({
foo: 1.bar: 2
})
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) / / 2
state.foo++
console.log(fooRef.value) / / 3
Copy the code
Above, the first argument of the toRef() method is the source object, and the second argument is the key string of the internal property. The value of the created ref object is changed, and the value in the source object is also changed
ToRef is useful when you need to pass a property in a reactive object to another function for use
setup(props) {
useSomeFeature(toRef(props, 'foo'))}Copy the code
toRefs()
This method converts a reactive object to a normal object, with each property in the resulting object pointing to the corresponding REF of the original object
const state = reactive({
foo: 1.bar: 2
})
const stateAsRefs = toRefs(state)
// The ref is already "linked" to the original property
state.foo++
console.log(stateAsRefs.foo.value) / / 2
stateAsRefs.foo.value++
console.log(state.foo) / / 3
Copy the code
ToRefs are useful when composite functions return reactive objects,
For example, the reactive function above packages the entire task into a function. Every time we refer to its properties, we need state.foo
In this case, we can use toRefs() to return the current data, and externally destruct the function to get the corresponding ref,
function useFeatureX() {
const state = reactive({
foo: 1.bar: 2
})
// Manipulate the logic of state
// Convert to ref when returned
return toRefs(state)
}
// Can be deconstructed without losing responsiveness
const { foo, bar } = useFeatureX()
Copy the code
isRef()
Check whether the value is a ref object
3 computed and watch
computed
Take a getter function as an argument and return an invariant responsive ref object from the value returned by the getter
const count = ref(1)
const plusOne = computed(() = > count.value + 1)
console.log(plusOne.value) / / 2
plusOne.value++ / / an error
Copy the code
Alternatively, he can use objects with get and set functions to create writable ref objects
const count = ref(1)
const plusOne = computed({
get: () = > count.value + 1.set: val= > count.value = val -1
})
// When plusOne is assigned, it is equivalent to passing in a parameter, val equals 1, and ref returns the result of the function
plusOne.value = 1
console.log(count.value) / / 0
Copy the code
watchEffect
A function is run immediately when its dependencies are tracked responsively, and rerunned when the dependencies are changed
const count = ref(0)
watchEffect(() = > {
console.log(count.value)
}) // logs 0
setTimeout(() = > {
count.value++
},1000)
// logs 1
// logs 2
// logs 3
// ...
Copy the code
watch
The Watch API is completely equivalent to the optional API this.$watch (and the corresponding Watch option) in that it listens to a specific data source and executes side effects in a separate callback function, which is also lazy by default, meaning that the callback is called only when the listening source has changed
- In contrast to watchEffect, Watch allows us to:
- Lazy execution side effects
- More specifically, the state that should trigger the listener to run again
- Access newVal and oldVal in the listening state
Listen to a single source
The listener data source can be either a getter function with a return value or a ref
// Listen for a getter
const state = reactive({ count: 0})
watch(
() = > state.count,
(newVal, oldVal) = > {
// ...})// Listen to a ref
const count = ref(0)
watch(count, (newVal, oldVal) = > {
// ...
})
Copy the code
Listen to multiple sources
Listeners can also use arrays to listen to multiple sources simultaneously:
watch([fooRef, barRef], ([newFoo, newBar], [oldFoo, oldBar]) = >{
// ...
})
Copy the code
Teleport portal
attribute
Teleport provides a clean way to control which parent node in the DOM is rendering the HTML without resorting to global state or splitting it into two components
To-string – Conditionally determines rendering and mounts the DOM in the teleport tag of the current component under the DOM of the specified class name
<teleport to="#some-id">.</teleport>
<teleport to=".some-class">.</teleport>
<teleport to="[data-teleport]">.</teleport>
Copy the code
Disable-boolean — This property can be used for disabled functions, which means that the slot contents will not be moved to any location, but will be rendered at the location you specified in the surrounding parent component
<teleport to='#popup' :disabled='displayVideoInline'>
<video src='./my-movie.mp4'/>
</teleport>
Copy the code
Note that this will move the actual DOM node, rather than being destroyed and recreated, and it will also keep the instance active state of any component instance, and all state HTML elements (that is, the video that plays) will keep their state
Using multiple Teleports on the same destination
A common usage scenario is a reusable component that may have multiple instances active at the same time, in which case multiple components can mount their contents to the same target element, and the order will be appending – the later mounts will follow the earlier mounts in the target element
<teleport to="#modals">
<div>A</div>
</teleport>
<teleport to="#modals">
<div>B</div>
</teleport>
<! -- result-->
<div id="modals">
<div>A</div>
<div>B</div>
</div>
Copy the code
Dynamically creating components
Within the parent component, we can dynamically create components that are inserted into the current DOM through control, and import components that currently need to be rendered
<template>
<component :is='bloolear ? Foo : Bar'/>
</template>
<script setup>
import Foo from './Foo.vue'
import Bar from './Bar.vue'
</script>
Copy the code
Custom instruction
1. Write and import
In addition to the default built-in instructions (V-Modul and V-show), vue3 also allows import when you need to perform low-level operations on normal DOM elements. Custom instruction
We can import a directive just as we would import a component, but note that it requires a v to be added to the naming method, which is a marker to improve code readability
For example, if we create a vfocus.js, the Mounted lifecycle is aligned with the calling component
export default {
// When the element bound to the directive is mounted to the DOM
mounted(el){
// The current element gets focus
el.focus()
console.log('Get the focus! '); }}Copy the code
Import within the required component, and call v-Focus directly within the input tag
<template> <input type="text" v-focus> </template> <script setup> import vFocus from '.. /vFocus.js'; </script>Copy the code
Another example: vhighlight.js
export default {
// When the element bound to the directive is mounted to the DOM
beforeMount(el, binding, vnode){
el.style.background = binding.value
}
}
Copy the code
< span style =" box-sizing: border-box; color: RGB (74, 74, 74); line-height: 20px; font-size: 13px! Important; white-space: inherit! Important;"Copy the code
This gets the corresponding variable in the current component before the element is rendered and passes the color to the directive to set the background color of the element
2. Customize the hook function of the directive API
The API is consistent with the components, as shown in:
-
Created: called before attributes of bound elements or event listeners are applied, useful when directives need to attach event listeners that need to be called before normal V-on event listeners.
-
Bind → beforeMount — called when a directive is first bound to an element and before the parent component is mounted
-
Inserted → Mounted — called after the parent component of the bound element is mounted
-
BeforeUpdate: New — called before updating the VNode that contains components
-
ComponentUpdated → UPDATE — called after the VNode that contains a component and its child components has been updated
-
BeforUnmount → New — called before the component or element is about to be removed
-
Unbind → Unmounted — called after the component or element is removed
Fragments
You can have multiple roots in Vue3
<template> <header>... </header> <main>... </main> <footer>... </footer> </template>Copy the code
Component communication
Props of the father the son
Similar to VUE2, properties declared on the parent component need to be passed to the child component, which needs to be bound on the component: child component property = ‘parent component property’, received in the child component via defindProps({key: value type})
// The parent component <template> <! -- 1. Events declared in the parent component, >< Props :fatherProps=" Props "></Props> </template> <script> import {ref} from 'vue' const Props= </script> <template> {{fatherProps}} </template> <script setup> import {withDefaults} from "vue"; DefineProps (['fatherProps']) // 2.2 defineProps({props1: String; props2: Number; DefineProps ({count1: {type: String, default: 'default'}, count2: {type: Number, default: 321 } }) </script>Copy the code
Emit the father
Vue3 provides an option for emits. Similar to props, this option is used to trigger the parent component event (child to parent).
// Subcomponent <template> <! -- 2. Bind native events to child components, triggering custom event names, $emit($emit($emit($emit($emit), $emit($emit), $emit($emit), $emit($emit), $emit($emit), STR)"> Trigger parent component event </button> </template> <script setup> import {ref} from 'vue' // 1. Const STR = ref(' string ') const emit = defineEmites(['my-click']) </script> </ template> <! -- 3. In the parent component, the child component label is bound to the trigger event name, Attribute value is the method in the current component --> < foo@my-click ='useFoo'></Foo> </template> <script setup> import Foo from './ foo.vue '// 3. Function useFoo(STR) {console.log(STR)} </script>Copy the code
Gets, calls, or changes state or methods within a child component
The child component label is bound to the ref property and gets the child component instance in the parent by exposing the variable or function in the child definExpose, and gets it through the ref.value.*
// The parent component <template> <! <Foo ref=' Foo '></Foo> < button@click ="getCount">getCount</button> </template> <script setup> import Foo from "./components/Foo.vue"; import { ref } from 'vue' // 2. Const foo = ref(null) const bb = ref('bb') function getCount() {// 4. Value = foo. Value = foo. A; foo.value.a = bbb; console.log(foo.value.a); foo.value.getName() } </script>Copy the code
// 1. A variable or function declared in a child component, <script setup> const a = ref('aaa') function getName() {console.log('name'); } defineExpose({ a, getName }) </script>Copy the code
Another method to export from a child component
You can import variables or methods from a child component to a parent component using the import method
impor Foo,{ useFoo } from './Foo.vue'
Copy the code
However, because of the setup syntax sugar, the child component throws a Setup object, and {useFoo} deconstructing does not work
At this point we can
/ / child components -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- < script > export function useFoo () {return} 'useFoo' export default {name: 'Foo', obj: { count: 100}} </script> <script setup> Above for the other a script script < / script > / / parent components -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - < the template > < button @ click = 'getFoo' > getFoo < / button > </template> <script setup> import Foo, { useFoo, a } from './Foo.vue' function getFoo() { console.log(useFoo()) // useFoo console.log(Foo.name) // Foo // ... } </script>Copy the code
Custom renderer CUSTome Renderer
Vue3.0 supports custom renderers. This API can be used to define rendering logic, such as rendering data to the canvas
Learn about…….. when you use it
Global API changed to instance method calls
Instance methods define components
Vue3 uses createApp to return the app instance, which exposes a number of global apis
// main.js
import { createApp, h } from 'vue'
import App from './App.vue'
createApp(App)
.component('comp', {
render() {
return h('div'.'I am comp')
}
})
.mount('#app')
Copy the code
Call the component directly from within the component through the label
<template>
<comp/>
</template>
Copy the code
Global and Internal APIs were reconfigured for tree shaking
Many of vuE2’s global apis hang directly on top of constructors as static functions, such as vue.nexttick (). If we never use them in our code, we form what’s called dead code. Useless code caused by such global apis cannot be eliminated using Tree-shaking of WebPack
import Vue from 'vue'
Vue.nextTick(() = > {
/ /...
})
Copy the code
Vue3 has made a change to extract them as separate functions so that the tree shaker of the packaging tool can exclude these dead codes
import { nextTick } from 'vue'
nextTick(() = > {
/ /...
})
Copy the code
Affected APIS:
- Vue.nextTick
- Vue.observable (replaced with vue.reactive) — Reactive data definition method
- Vue.version — Method of determining the version
- Vue.com compile (in full version only) – method for doing compilation
- Vue.set (in compatible version only)
- Vue.delete (compatible version only)
Changes in v-Model use
Bidirectional binding of child components
In VUE2, the. Sync and V-Model functions overlap and can be easily confused, but in VUE3 they are unified
In Vue 3, the API for bidirectional data binding has been standardized, reducing confusion and giving developers more flexibility when using v-Model directives.
The parent passes the value back to the child and allows the child to return the value back to the parent
// parent <template> <comp v-model='counter'></comp> </template> <script setup> import {ref} from 'vue' const counter = Ref (0) </script> <template> <div @click="$emit('update:modelValue', modelVlaue + 1)"> {{modelValue}} </div> </template> <script setup> import { definProps } from 'vue' definProps({ modelValue:{ type: Number, default: 0 } }) </script>Copy the code
In VUE3, v-Model on a custom component is equivalent to passing a modelValue Prop and receiving the update:modelValue event thrown:
<ChildComponent v-model="pageTitle" />
<! --> -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
Copy the code
V – model parameters
If we need to change the modelValue name as an alternative to the modelValue option in the component, we can now pass an argument to the V-Model
v-model:xxx=”xxx”
<ChildComponent v-model:title="pageTitle" />
<! --> -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Copy the code
This can also be used as an alternative to the.sync modifier and allows us to use multiple V-Models on our custom components
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<! --> -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
Copy the code
This and the passed parameters are triggered by an event in the child component and updated to the parent component
<template>
<div @click="$emit('update:pageTitle', pageTitle + 1)">
counter: {{pageTitle}}
</div>
</template>
<script setup>
import { definProps } from 'vue'
definProps({
pageTitle:{
type: Number,
default: 0
}
})
</script>
Copy the code
Asynchronous component usage changes
To reduce the size of the program and optimize load speed, components need to be imported asynchronously only when they need to be rendered
Because functional components in VU3 must be defined as pure functions, there is a change in the definition of asynchronous components:
- You must explicitly use the defineAsyncComponent package
- Component option to rename to Loader
- The Loader function no longer accepts resolve and reject and must return a Promise
Define an asynchronous component with no configuration
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncCompomemt(() = >('./components/AsyncComp.vue'))
Copy the code
Define an asynchronous component with a configuration. The Loader option is the previous Component
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
const AsyncComp = defineAsyncComponent({
loader: () = > import('./components/AsyncComp.vue'),
delay: 200.timeout: 3000.errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
Copy the code
User-defined component whitelist
Custom element detection in VUE3 occurs when the template is compiled. If you want to add some custom elements outside of VUE, you need to set the isCustomElement option in the compiler options
When using the build tool, templates are precompiled using the Vue-Loader. Just set the compilerOptions it provides, vue.config.js
rules: [
{
test: /\.vue$/,
use: 'vue=loader'.options: {
compolerOptions: {
// Receive a tag that equals XXX and ignore the problem, eliminating the warning
isCustomElement: tab= > tag === 'plastic-button'}}}]Copy the code
In the vite project, configure vueCompilerOptions in the vite.config.js:
module.exports = {
vueCompilerOptions: {
isCustomElement: tag= > tag === 'plastic-button'}}Copy the code
$scopedSlots
The attribute is removed and replaced with $slots
$slots and scope slots are changed from $slots to $slots.
- Slots are exposed as functions
- $scopdSlots removed
Access the slot contents as a function, mylink.vue
<script>
import { h } from 'vue'
export default {
props: {
to: {
type: String,
required: true
},
},
render() {
return h("a", { href: this to }, this.$slots.default());
},
}
</script>
Copy the code
Transition class name change
Vue2 writing is not uniform, vuE3 made corrections
- V-enter → v-enter-from – corresponding – v-enter-to —- v-enter-active (transition)
- V-leave → v-leave-from — corresponding — v-leave-to —- v-leave-active
The component Watch option and instance method $watch no longer support dot delimiter string paths
Expressions separated by. Are no longer supported by watches and watches. You can use a computed function for watch, you can use a computed function for watch, you can use a computed function for watch, and you can use a computed function for watch
this.$watch(() = > this.foo.bar, (v1, v2) = > {
console.log(this.foo.bar)
})
Copy the code
KeyCode as a V-ON modifier has been removed
Vue2 can use keyCode to refer to a key, but vuE3 no longer supports it due to poor readability
<! -- keyCode mode is no longer supported -->
<input v-on:keyup.13="submit" />
<! -- Use alias only -->
<input @keyup.enter="submit" />
Copy the code
$on
.$off
和 $once
remove
The above three methods are not considered to be provided by VUE, so they are removed, and event dispatch and listening can be implemented using other third-party libraries
npm i mitt -S
Copy the code
/ / create the emitter
const emitter = mitt()
// Send the event
emitter.emit('foo'.'fooooooo')
// Listen for events
emitter.on('foo'.msg= > console.log(msg))
Copy the code
The filter to remove
The filter has been removed from vue3, call a method or calculate a property instead