preface
This article shares changes in vue 3.x usage, not code implementation.
The setup(){} function has been added, and almost all configurations are now defined as functions. Even so, there are a lot of small changes. This article mainly shares some common usage differences between vue 2.x and vue 3.x. It’s not much, but it’s not much. Source: github.com/vuejs/rfcs/…
Of course, this assumes that you are already familiar with vue 2.x, so let’s take a look.
new
composition-api
1. Logic reuse and code organization
This is a core change in VUE 3.0. In addition to changing the way we write state definitions, it also gives us a better experience of logic reuse and code organization. The new way allows you to put all the code (states, computed properties, methods, etc.) of the same business logic together. This might sound like a bit of a no-brainer, but if you’ve ever written a complex component, you’ll see that this is a good one. The old created and beforeCreated hook functions are deprecated and replaced with setup in VUE 3.0.
2. Better type inference
Better support for TypeScript.
Check out this article: github.com/vuejs/rfcs/…
Or read this: Vue-composition-api-rfc.netlify. app/zh/
Complete API:vue-composition-api-rfc.net lify. App/useful/API. The HTML
Teleport components
The Teleport component simply transfers the content defined within it to the target element. There are no redundant elements in the element structure, and of course it does not affect the component tree. It is transparent. Why have this component? For a better code organization experience. For example, sometimes part of a component template logically belongs to that component, but from a technical point of view (e.g., styling requirements), it is best to move that part of the template to another location in the DOM.
For example, some UI component libraries require z-Index to control the hierarchy of modal Windows, dialogs, notifications, drop-down menus, etc. If they are only in different component or element levels, then the hierarchy order of Z-Index cannot be guaranteed. You might say aren’t a lot of UI libraries already implemented this way? As for how the UI library is implemented, MY guess is to manipulate the DOM directly. Why provide the Teleport component? Perhaps because of the mission of Vue itself: to minimize direct manipulation of the DOM by developers, it’s all done by VUE. Developers can spend more time on business development.
<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
For more details: github.com/vuejs/rfcs/…
Suspense
Load asynchronous components. Suspense displays the contents of the #fallback slot until the asynchronous components are fully loaded and rendered.
<Suspense>
<template>
<Suspended-component />
</template>
<template #fallback>
Loading...
</template>
</Suspense>
Copy the code
#fallback is shorthand for the plugin v-solt, and the first template is not given, which is the default slot.
change
Slot slot syntax
Github.com/vuejs/rfcs/…
Applicable versions: Version: 2.x, Version: 3.x
Future versions of VUE can be said to merge (slot and slot-scope)
<! -- vue 2.x -->
<foo>
<bar slot="one" slot-scope="one">
<div slot-scope="bar">
{{ one }} {{ bar }}
</div>
</bar>
<bar slot="two" slot-scope="two">
<div slot-scope="bar">
{{ two }} {{ bar }}
</div>
</bar>
</foo>
<! -- vue 3.x -->
<foo>
<template v-slot:one="one">
<bar v-slot="bar">
<div>{{ one }} {{ bar }}</div>
</bar>
</template>
<template v-slot:two="two">
<bar v-slot="bar">
<div>{{ two }} {{ bar }}</div>
</bar>
</template>
</foo>
Copy the code
I think it’s a good thing, it’s one, it’s not a bit confusing.
shorthand
<TestComponent>
<template #one="{ name }">Hello {{ name }}</template>
</TestComponent>
Copy the code
Instruction dynamic parameter
Applicable versions: Version: 2.x, Version: 3.x
<! -- v-bindwith dynamic key -->
<div v-bind:[key] ="value"></div><! -- v-bind shorthandwith dynamic key -->
<div :[key] ="value"></div><! -- v-onwith dynamic event -->
<div v-on:[event] ="handler"></div><! -- v-on shorthandwith dynamic event -->
<div@ [event] ="handler"></div><! -- v-slotwith dynamic name -->
<foo>
<template v-slot:[name] >
Hello
</template>
</foo><! -- v-slot shorthandwith dynamic name -->
<! -- pending #3 -->
<foo>
<template# [name] >
Default slot
</template>
</foo>
Copy the code
In short, directive names, event names, and slot names can be defined using variables.
Tree-shaking
Applicable Version: Version: 3.x
Vue 3 does not package all apis, only the apis you use
<! -- vue2.x -->
import Vue from 'vue'
Vue.nextTick((a)= > {})
constobj = Vue.observable({}) <! -- vue3.x -->
import Vue, { nextTick, observable } from 'vue'
Vue.nextTick // undefined
nextTick((a)= > {})
const obj = observable({})
Copy the code
That is, we will package whatever we use in the project, not the entire API like vue 2.x.
Sync big change
Version: Vue 3.x
<! -- vue 2.x -->
<MyComponent v-bind:title.sync="title" />
<! -- vue 3.x -->
<MyComponent v-model:title="title" />
Copy the code
That said, VUE 3.0 removed.sync and incorporated it into the V-Model, and the internal implementation of the V-Model has also been tweaked
The element
<input v-model="xxx">
<! -- would be shorthand for: -->
<input
:model-value="xxx"
@update:model-value="newValue => { xxx = newValue }"
>
Copy the code
component
<MyComponent v-model:aaa="xxx"/ > <! -- would be shorthand for: --> <MyComponent :aaa="xxx" @update:aaa="newValue => { xxx = newValue }" />Copy the code
However, it seems that the group alpha version does not support V-model :aaa=” XXX”
Function component
Version: Vue 3.x
<! -- vue2.x -->
const FunctionalComp = {
functional: true,
render(h) {
return h('div'.`Hello! ${props.name}`)}} <! -- vue3.x -->
import { h } from 'vue'
const FunctionalComp = (props, { slots, attrs, emit }) = > {
return h('div'.`Hello! ${props.name}`)}Copy the code
The functional:true option is no longer required, and
is no longer paid
Asynchronous components must also be created through API methods
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent((a)= > import('./Foo.vue'))
Copy the code
Global API
Version: Vue 3.x
The vue 2. X
import Vue from 'vue'
import App from './App.vue'
Vue.config.ignoredElements = [/^app-/]
Vue.use(/ *... * /)
Vue.mixin(/ *... * /)
Vue.component(/ *... * /)
Vue.directive(/ *... * /)
Vue.prototype.customProperty = (a)= > {}
new Vue({
render: h= > h(App)
}).$mount('#app')
Copy the code
The vue 3. X
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.config.isCustomElement = tag= > tag.startsWith('app-')
app.use(/ *... * /)
app.mixin(/ *... * /)
app.component(/ *... * /)
app.directive(/ *... * /)
app.config.globalProperties.customProperty = (a)= > {}
app.mount(App, '#app')
Copy the code
As you can see, the way instances are created has also changed. Some of the global API methods are no longer global, but placed on instances.
More changes can be seen here: github.com/vuejs/rfcs/…
v-model
Applicable Version: Version 3.x
1. Keep the original way
<input v-model="foo">
Copy the code
2. Multiple V-Models can be bound
<InviteeForm
v-model:name="inviteeName"
v-model:email="inviteeEmail"
/>
Copy the code
In fact, the above method is equivalent to.sync.
3. Extra processing
<Comp
v-model:foo.trim="text"
v-model:bar.number="number" />
Copy the code
We can add extra processing to this property
The hook function of the directive
Applicable Version: Version 3.x
The directive’s hook function in Vue 3.x mimics the naming of hook functions in components
Vue 2. X
const MyDirective = {
bind(el, binding, vnode, prevVnode) {},
inserted() {},
update() {},
componentUpdated() {},
unbind() {}
}
Copy the code
Vue 3.0
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
Copy the code
transition
Applicable Version: Version 3.x
External switches do not trigger transitions when
vue 2.x
<! -- modal component -->
<template>
<transition>
<div class="modal"><slot/></div>
</transition>
</template>
<! -- usage -->
<modal v-if="showModal">hello</modal>
Copy the code
vue 3.x
<! -- modal component -->
<template>
<transition>
<div v-if="show" class="modal"><slot/></div>
</transition>
</template>
<! -- usage -->
<modal :show="showModal">hello</modal>
Copy the code
That means we can only use transitions in
transition-class
Rename two transition classes
Rename v-enter to v-enter-from, and rename v-leave to v-enter-from.
.v-enter-from..v-leave-to {
opacity: 0;
}
.v-leave-from..v-enter-to {
opacity: 1
}
Copy the code
Router
Version: Vue (2.x / 3.x) Vue Router (3.x / 4.x)
The router – the link changes
Router-link adds the Scoped-Slot API and custom attributes, and removes the tag and event attributes.
What is the use of adding scoped-slot? With scoped-slot, we have the flexibility to customize elements based on the state returned by scoped-slot, both style and class.
<router-link to="/" custom v-slot="{ href, navigate, isActive }">
<li :class="{ 'active': isActive }">
<a :href="href" @click="navigate">
<Icon>home</Icon><span class="xs-hidden">Home</span>
</a>
</li>
</router-link>
Copy the code
In other words, the new Router is more pure, giving us parameters that we can use to implement different scenarios.
Meta merger
{
path: '/parent'.meta: { requiresAuth: true.isChild: false },
children: [{path: 'child'.meta: { isChild: true}}}]Copy the code
When accessing /parent/child, the meta in the child path is as follows:
{ requiresAuth: true.isChild: true }
Copy the code
The merge strategy is similar to object.assign
Routes match all
const routes = [
{
path: '/'.name: 'Home'.component: (a)= > import(/* webpackChunkName: "Home" */ '.. /views/Home.vue')}, {path: '/about'.name: 'About'.component: (a)= > import(/* webpackChunkName: "about" */ '.. /views/About.vue')}, {path: '/:catchAll(.*)'.name: 'All'.component: (a)= > import(/* webpackChunkName: "All" */ '.. /views/Home.vue')}]Copy the code
One thing to note here is that vue-router matching all routes has been changed, not the old version *. In the new version, we refer to the example code above
Obtain the current route information
import router from '.. /router'
export default {
setup () {
const currentRoute = router.currentRoute.value
console.log(currentRoute)
}
}
Copy the code
The router introduced is the object we created with the createRouter() method
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes
})
Copy the code
The Routes route defines an array of routes for us, as in the old version.
Style scoped
Applicable versions: Version: 2.x, 3.x
The old version
Depth selector / * * / / * a: * / > > > the foo {} / * way 2: * / / deep/foo {} / * 3 * / : : v - deep. Foo {}Copy the code
The new version
/* Depth selector */
::v-deep(.foo) {}
Copy the code
In addition to the depth selector above, there are the following two, written similarly.
/* slot content works */
::v-slotted(.foo) {}
/ * * / global
::v-global(.foo) {}
Copy the code
Attribute value modification
Applicable Version: Version: 3.x
Vue itself handles the attributes of the element accordingly. This is handled in older versions of VUE:
expression | normal | Finally processed into |
---|---|---|
:attr="null" |
/ | draggable="false" |
:attr="undefined" |
/ | / |
:attr="true" |
foo="true" |
draggable="true" |
:attr="false" |
/ | draggable="false" |
:attr="0" |
foo="0" |
draggable="true" |
attr="" |
foo="" |
draggable="true" |
attr="foo" |
foo="foo" |
draggable="true" |
attr |
foo="" |
draggable="true" |
New version processing mode:
expression | normal | Finally processed into |
---|---|---|
:attr="null" |
/ | / |
:attr="undefined" |
/ | / |
:attr="true" |
foo="true" |
draggable="true" |
:attr="false" |
foo="false" |
draggable="false" |
:attr="0" |
foo="0" |
draggable="0" |
attr="" |
foo="" |
draggable="" |
attr="foo" |
foo="foo" |
draggable="foo" |
attr |
foo="" |
draggable="" |
In the new version, it basically stays the same, that is, what attribute values we add to the element, preferably after vUE processing.
Asynchronous components
import { defineAsyncComponent } from "vue"
// simple usage
const AsyncFoo = defineAsyncComponent((a)= > import("./Foo.vue"))
Copy the code
It’s written a little bit differently than before.
Dynamic routing
Version Router 4
Several methods have been added
router.addRoute(route: RouteRecord)
Dynamically Adding routesrouter.removeRoute(name: string | symbol)
To dynamically delete routesrouter.hasRoute(name: string | symbol): boolean
To check whether the route existsrouter.getRoutes(): RouteRecord[]
Obtaining the Routing List
router.addRoute({
path: '/new-route'.name: 'NewRoute'.component: NewRoute
})
// add to the children of an existing route
router.addRoute('ParentRoute', {
path: 'new-route'.name: 'NewRoute'.component: NewRoute
})
router.removeRoute('NewRoute')
// normalized version of the records added
const routeRecords = router.getRoutes()
Copy the code
Details: github.com/vuejs/rfcs/…
emits-option
const Foo = defineComponent({
emits: {
submit: (payload: { email: string; password: string }) = > {
// perform runtime validation}},methods: {
onSubmit() {
this.$emit('submit', {
email: '[email protected]'.password: 123 // Type error!
})
this.$emit('non-declared-event') // Type error!}}})Copy the code
The usage of the $emit() method remains the same, but additional emits objects are required. Note that TypeScript is not yet supported in the alpha version
Number of component root elements
Vue 3 components no longer limit the number of root elements in a template (previous versions had only one root element).
Vue 3.x is deprecated
- BeforeCreate, created
- filters
- keycode
- inline-template
- data-object
- Off and $once
By the end of this article I’m sure you have a basic understanding of VUE 3. While this article doesn’t make you an instant driver of Vue 3.x, it does give you an implicit experience of some of the new vue 3.x features. In particular, you can read about the Composition API, even if it’s not written in detail in this article, with additional links. I think the Composition API is really cool.
Vue plan
Github.com/vuejs/vue/p…