Up to now, vuE3 has been officially launched, so we are going to have a complete understanding of it.
And then the more important parts of it were organized into this document,
This document is only streamlined, not in-depth
proxy
To better intercept object/array changes, vue’s underlying implementation of bidirectional binding also abandoned Object.defineProperty in favor of proxy
The drawback of Object.defineProperty is that it does not listen for new fields of the object. Vue initialization also takes a lot of time to recursively mount each property of the object, which results in vue2’s limitation of using $set to set new fields. It also needs to hack away the array push, replace and other methods, so VUe3 also chooses a better proxy
The global method
// Vue 2.x
Vue.prototype.$http = () = > {}
// Vue 3
const app = createApp({})
app.config.globalProperties.$http = () = > {}
Copy the code
composition api
The properties of objects in VUe2 have been stripped out of vue3 and made available to developers in the form of composition API, thus better supporting tree Sharking, i.e. apis that are not used when packaging are not entered
ref
Wrap basic types, and of course pass in objects (call reactive internally)
To change the value of ref, pass.value
import { ref } from 'vue'
const count = ref(2)
/ / modify
count.value = 3
Copy the code
reactive
For reference types, unlike ref, it does not need to pass.value
import { reactive } from 'vue'
const person = reactive({ name: 'Joe'.age: 18 })
/ / modify
person.name = 'bill'
Copy the code
isRef
Determine if a value was created by ref
import { ref, isRef } from 'vue'
const count = ref(2)
isRef(count) // true
Copy the code
toRef
Treating a value of Reactive to a REF maintains a reactive connection to its original reactive
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
toRefs
Each value of Reactive is treated as a REF, mostly to facilitate the use of values in Reactive in templates
export default {
setup() {
// Can be destructed without losing responsiveness
const state = reactive({
foo: 1.bar: 2
})
return {
...toRefs(state)
}
}
}
Copy the code
isReactive
See if it’s reactive
readonly
Receive a REF or Reactive and return a read-only, reactive new object
const original = reactive({ count: 0 })
const copy = readonly(original)
copy.count++ / / warning!
Copy the code
watchEffect
Execute a function passed in immediately, trace its dependencies responsively, and re-run the function when its dependencies change.
const count = ref(0)
watchEffect(() = > console.log(count.value))
// -> logs 0
setTimeout(() = > {
count.value++
// -> logs 1
}, 100)
Copy the code
watch
In contrast to watchEffect, Watch allows us to:
- Lazy execution of side effects;
- Be more specific about the state in which the listener should be triggered to restart;
- Accesses the previous and current values of the monitored state.
/ / website demo
// Listen for a getter
const state = reactive({ count: 0 })
watch(() = > state.count, (count, prevCount) = > {
/ *... * /})// Listen directly on a ref
const count = ref(0)
watch(count, (count, prevCount) = > {
/ *... * /
})
// Listen on multiple sources
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) = > {
/ *... * /
})
Copy the code
computed
const count = ref(1)
const plusOne = computed(() = > count.value + 1)
// Customize get set
const plusOne = computed({
get: () = > count.value + 1.set: val= > {
count.value = val - 1}})Copy the code
filter
Filters are no longer supported and are recommended to be replaced with method calls or computed properties
/ / website demo
<template>
<p>{{ accountInUSD }}</p>
</template>
<script>
export default {
props: {
accountBalance: {
type: Number.required: true}},computed: {
accountInUSD() {
return '$' + this.accountBalance
}
}
}
</script>
Copy the code
You can also use the JS native pipe operators
// same as plus(123)
<template>
<p>{{ 123 |> plus }}</p>
</template>
<script>
export default {
setup() {
function plus(val) {
return val + 100
}
return {
myFormat
}
}
}
</script>
Copy the code
The life cycle
- beforeCreate -> setup
- created -> setup
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeUnmount -> onBeforeUnmount
- unmounted -> onUnmounted
- errorCaptured -> onErrorCaptured
teleport
A portal that renders the DOM inside the component into the specified container.
Usage scenario: Modal pop-ups don’t have to pop up inside components anymore
The to argument takes a selector for the specified DOM, and supports multiple simultaneous uses, which will be appended to and appear together
<div id="modal"></div>
<teleport to="#modal" >
<div>a</div>
</teleport>
<teleport to="#modal" >
<div>b</div>
</teleport>
/ / the result
<div id="modal">
<div>a</div>
<div>b</div>
</div>
Copy the code
CSS depth selector
:deep()
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
Copy the code
The above code will compile to:
.a[data-v-f3f3eg9] .b {
/ *... * /
}
Copy the code
css v-bind
Single-file component
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
Copy the code
This syntax also works with < Script Setup > and supports JavaScript expressions (need to be enclosed in quotes)
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<p>hello</p>
</template>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
Copy the code
style module
The
<template>
<p :class="$style.red">
This should be red
</p>
</template>
<style module>
.red {
color: red;
}
</style>
Copy the code
Ref array
In Vue 2, the ref attribute used in v-for populates the corresponding $refs property with the REF array. When there are nested V-fors, this behavior becomes ambiguous and inefficient.
In Vue 3, this usage will no longer automatically create $ref arrays. To get multiple refs from a single binding, bind the ref to a more flexible function (which is a new feature) :
<div v-for="item in list" :ref="setItemRef"></div>
export default {
data() {
return {
itemRefs: []}},methods: {
setItemRef(el) {
if (el) {
this.itemRefs.push(el)
}
}
},
beforeUpdate() {
this.itemRefs = []
},
updated() {
console.log(this.itemRefs)
}
}
Copy the code
Combined API:
import { onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
let itemRefs = []
const setItemRef = el= > {
if (el) {
itemRefs.push(el)
}
}
onBeforeUpdate(() = > {
itemRefs = []
})
onUpdated(() = > {
console.log(itemRefs)
})
return {
setItemRef
}
}
}
Copy the code
fragment
Multiple root nodes are allowed
<template>
<a>.</a>
<b>.</b>
<c>.</c>
</template>
Copy the code
The data options
Vue2: Data can be object or function
Vue3: Normalized to accept only functions that return object
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
Copy the code
Mixins merge behavior changes
When data() from a component and its mixin or extends base class are merged, the merge operation is now performed shallowly:
const Mixin = {
data() {
return {
user: {
name: 'Jack'.id: 1}}}}const CompA = {
mixins: [Mixin],
data() {
return {
user: {
id: 2}}}}Copy the code
In Vue 2.x, the generated $data is:
{
"user": {
"id": 2."name": "Jack"}}Copy the code
In 3.0, the result will be:
{
"user": {
"id": 2}}Copy the code
Remove $listeners
In Vue 3, event listeners are considered attributes prefixed only with on, so that they become part of the attrs object, and therefore part of the attrs object, and therefore part of the attrs object, and therefore listeners are removed.
emits
You need to log all events fired by each component using emits. Vue3 removed the. Native modifier. Any event listeners not declared in emits are counted in the component’s $attrs and bound to the root node of the component by default.
<template> <div> <p>{{ text }}</p> <button v-on:click="$emit('accepted')">OK</button> </div> </template> <script> export default { props: ['text'], emits: ['accepted'] } </script>Copy the code
v-on.native
Vue will now add all event listeners in a child component that are not defined to be triggered by the component as native event listeners to the root element of the child component (unless inheritAttrs: False is set in the child component’s options).
Take the click event as an example. Now if you want @click.native, you don’t need to write ‘click’ in the child component’s emits
v-model
Supports multiple V-models, which can be customized to receive props values
// Parent <ChildComponent v-model:title="pageTitle" v-model:content="pageContent" /> <! -- is short for: --> <ChildComponent :title="pageTitle" @update:title="pageTitle = $event" :content="pageContent" @update:content="pageContent = $event" />Copy the code
Vue export default {props: {modelValue: String}, emits: ['update:modelValue'], methods: $emit('update:modelValue', title) {this.$emit('input', title) '}}Copy the code
Conclusion:
Accept: just props, such as name and age
Submit: update: start, emit(‘update:name’, value), emit(‘update:age’, value)
External use: v-model:name=” XXX “V-model :age=”aaa”
Event apis
The on, ON, ON, off, and $once instance methods have been removed, and the component instance no longer implements the event-triggering interface.
Custom instruction
Target event and lifecycle unification
Created - New! Called before an attribute or event listener for an element is applied. Bind → beforeMount inserted → mounted beforeUpdate: Add! Called before the element itself is updated, much like a component's lifecycle hook. Update → Remove! The hook has so much in common with the updated that it is redundant. Please use the updated version instead. ComponentUpdated → Updated beforeUnmount: Added! Similar to a component's lifecycle hook, it is called before the element is unloaded. unbind -> unmountedCopy the code
Asynchronous components
In Vue 3, since functional components are defined as pure functions, asynchronous components need to be explicitly defined by wrapping them in the new defineAsyncComponent helper method:
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// Asynchronous components with no options
const asyncModal = defineAsyncComponent(() = > import('./Modal.vue'))
// Asynchronous components with options
const asyncModalWithOptions = defineAsyncComponent({
loader: () = > import('./Modal.vue'),
delay: 200.timeout: 3000.errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
Copy the code
Suspense
Asynchronous component processing scenarios within components
Nodes in the default slot are displayed as much as possible. If not, the nodes in the Fallback slot are displayed.
<template>
<suspense>
<template #default>
<todo-list />
</template>
<template #fallback>
<div>
Loading...
</div>
</template>
</suspense>
</template>
<script>
export default {
components: {
TodoList: defineAsyncComponent(() => import('./TodoList.vue'))
}
}
</script>
Copy the code
The default slot places your original components
Fallback slot places loading when the component is not properly loaded
Render function API
Vue2 is the h function received in render(h){} function, when we need to reuse method need to pass h, very inconvenient
The vue3 h function was removed from the ‘vue’ package, the render function no longer receives it
import { h, reactive } from 'vue'
Copy the code
V-bind merge behavior
In 2.x, if an element defines both v-bind=”object” and an identical independent attribute, that independent attribute always overrides the binding in object.
<! -- -- -- > templates
<div id="red" v-bind="{ id: 'blue' }"></div>
<! Results - - - >
<div id="red"></div>
Copy the code
In 3.x, if an element defines both V-bind =”object” and the same independent attribute, the order in which the bindings are declared determines how they are merged. In other words, developers now have more control over what they want to merge than if they assumed that they always want separate attributes to override what is defined in Object.
<! -- -- -- > templates
<div id="red" v-bind="{ id: 'blue' }"></div>
<! Results - - - >
<div id="blue"></div>
<! -- -- -- > templates
<div v-bind="{ id: 'blue' }" id="red"></div>
<! Results - - - >
<div id="red"></div>
Copy the code
VNode life cycle events
// vue2
<template>
<child-component @hook:updated="onUpdated">
</template>
Copy the code
Vue3 <template> <child-component @vnode-updated="onUpdated"> </template> // camelback <template> <child-component @vnodeUpdated="onUpdated"> </template>Copy the code
Lifecycle event listening mode changed from @hook: to @vnode-
Transition class name change
vue2
.v-enter..v-leave-to {
opacity: 0;
}
.v-leave..v-enter-to {
opacity: 1;
}
Copy the code
Vue3 was renamed to
.v-enter-from..v-leave-to {
opacity: 0;
}
.v-leave-from..v-enter-to {
opacity: 1;
}
Copy the code
Accessed in prop’s default function
Factory functions that generate prop defaults can no longer access this.
Instead:
The raw prop received by the component is passed as an argument to the default function;
Inject API is available in default functions.
import { inject } from 'vue'
export default {
props: {
theme: {
default (props) {
// 'props' is passed to the component,
// The original value before any type/default cast,
// The injected property can also be accessed using 'inject'
return inject('theme'.'default-theme')}}}}Copy the code
Listen to the array
When you listen on an array with the Watch option, the callback is triggered only if the array is replaced. In other words, listening callbacks will no longer be fired when the array is changed. To trigger a listening callback when an array is changed, you must specify the deep option.
{
watch: {
bookList: {
handler(val, oldVal) {
console.log('book list changed')},deep: true}}}Copy the code