Vue3.0 Learning Suggestions
For those who have learned vue2.0
Vue3.0 new features
Chinese document
- Composition Api (Core)
- V – model changes
- Usage on key node of V-for changed
- V-if and V-for have higher priority for the same element
- Ref internal V-for no longer registers reference arrays
- Functional components can only be created using normal functions
- Asynchronous components are required
defineAsyncComponent
Create method - All slots pass
$slots
- in
destroyed
The lifecycle option has been renamed tounmounted
- in
beforeDestroy
The lifecycle option has been renamed tobeforeUnmount
- .
Advantages and disadvantages Vue3.0
Advantages:
- The vast majority of Vue internal API external exposure, so that Vue has the ability to develop large projects, such as compile compile API
- Treeshaking for Webpack (Tree Shaking is DCE’s way of ignoring unused code when packaging.) Support friendly
- Using Proxy for reactive variable definition improves performance by 1.2~2 times
- SSR is two to three times faster
- You can use the composition-API plug-in in Vue2.0 alone, or you can develop plug-ins with it directly
- More friendly to typescript support
- For the future: For Yu Creek’s recently innovated Vite development server (a high-performance development server that abandons Webpack and uses the UNDERLYING Koa framework), directly use the Vue3.0 syntax
Disadvantages:
- Only Internet Explorer 11 or later is supported
- For developers who are used to the Vue2.0 development mode, it will increase the mental burden and experience the developer’s code organization ability
It’s also an opportunity to develop your capabilities. I particularly like the Vue author’s design philosophy: let developers grow with the framework
Experience the four poses of Vue3.0
For now, there are four postural portals to experience Vue3.0
-
Through the CDN: < script SRC = “https://unpkg.com/vue@next” > < / script >
-
Playground via Codepen’s browser
-
Scaffolding Vite:
npm init vite-app hello-vue3 # OR yarn create vite-app hello-vue3 Copy the code
A new tool developed by UHP, intended to replace WebPack in the future, was originally developed to take advantage of browsers that now support ES6 import; When an import is encountered, it sends an HTTP request to load the corresponding file. Vite intercepts these requests and precompiles them, eliminating webPack’s lengthy packaging events and improving the development experience.
-
Scaffolding vue – cli
npm install -g @vue/cli # OR yarn global add @vue/cli vue create hello-vue3 # select vue 3 preset Copy the code
Global API
New global API: createApp
Calling createApp returns an application instance, which is a new concept in Vue3.0:
Open the SRC/main. Js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
Copy the code
The application instance exposes a subset of the current global API. As a rule of thumb, any API that globally changes the behavior of the Vue will now be moved to the application instance app. Here is a table of the current global API and its corresponding instance API:
2. X global API | 3.x instance API (app ) |
---|---|
Vue.config | app.config |
Vue.config.productionTip | removedHas been removed |
Vue.config.ignoredElements | app.config.isCustomElement |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Composition API learning
The official website
setup
The setup function is a new component option. Act as an entry point for using the Composition API within a component
Create the component instance, initialize props, and then call the setup function. It is called before the beforeCreate hook.
Setup returns an object. All properties of the object, which are reactive data, can be used directly in the template. Equivalent to the object returned by the data function in Vue2.0.
App.vue
<script>
export default {
setup () {
return{}}}</script>
Copy the code
Responsive data
- Ref: Can pass in any type of value and return a responsive and mutable REF object. The REF object has a single attribute that points to an internal value
.value
The value attribute must be used when changing a value - Reactive: A reactive proxy that accepts a common object and returns that common object. Equivalent to 2.x
Vue.obserable()
In short: Reactive is responsible for complex data structures, and REF can wrap basic data structures into responsive form
reactive
<template>
<div>
<h2>{{state.count}}</h2>
<button @click="add">To calculate</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
setup(){
Reactive is responsible for complex data structures,
const state = reactive({
count: 1
});
function add() {
state.count++;
}
return{ state, add}; }};</script>
Copy the code
ref
<template>
<div>
<h2>{{state.count}}</h2>
<h3>{{num}}</h3>
<button @click="add">To calculate</button>
</div>
</template>
<script>
import { reactive, ref } from "vue";
export default {
setup(){
const state = reactive({
count: 1
});
const num = ref(0);
function add() {
state.count++;
num.value+=2
}
return{ state, add, num }; }};</script>
Copy the code
Num can be used directly in the template, but the.value attribute can be used when changing js.
toRefs
Converts a reactive object to a normal object, where each property of the resulting object points to the corresponding property of the original object
ToRefs is useful when returning a reactive object from a synthesized function so that the consuming component can decompose/diffuse the returned object without losing the reactive:
useFeatureX.js
import {reactive} from 'vue';
export function userFeatureX(){
const state = reactive({
foo: 1.bar: 2
})
// Logical running status
// Convert to ref on return
return state;
}
Copy the code
App.vue
import {toRefs} from 'vue'
export default {
setup(){
const state = useFeatureX();
return {
...toRefs(state)
}
}
}
Copy the code
computed
Pass in a getter function that returns a ref object that cannot be manually modified by default.
import { reactive, ref, computed } from "vue";
export default {
setup() {
Reactive is responsible for complex data structures.
const state = reactive({
count: 1
});
// 2.ref can wrap basic data structures in response form
const num = ref(0);
// 3. Create a read-only compute property
const computedEven1 = computed(() = > state.count % 2);
// 4. Create readable and writable computed properties
const computedEven2 = computed({
get:() = >{
return state.count % 2;
},
set: newVal= >{ state.count = newVal; }})// Declaration of the event
function add() {
state.count++;
num.value += 2;
}
function handleClick() {
computedEven2.value = 10;
}
return{ state, add, num, computedEven1,computedEven2,handleClick }; }};Copy the code
watchEffect
Execute a function passed in immediately, trace its dependencies responsively, and re-run the function when its dependencies change.
const num = ref(0)
watchEffect(() = > console.log(count.value))
// -> print out 0
setTimeout(() = > {
count.value++
// -> print 1
}, 100)
Copy the code
-
Stop listening
Implicit stop
When watchEffect is called on a component’s setup() function or lifecycle hook, the listener is linked to the component’s lifecycle and stops automatically when the component is uninstalled
According to stop
In some cases, you can also display the return value of the call to stop listening
const stop = watchEffect(() = >{ / *... * / }) // Stop listening stop() Copy the code
-
Clearance side effect
Sometimes side effects functions perform asynchronous side effects, and these responses need to be cleared when they fail (that is, the state has changed before completion). You can take an onInvalidate function as an argument in the function that listens for side effects incoming to register a callback in case of a cleanup failure. This invalidation callback is triggered when:
- When the side effect is about to be re-executed
- The listener is stopped (if in
setup()
Or the lifecycle hook functionwatchEffect
, when uninstalling components)
Examples from the official website:
watchEffect((onInvalidate) = > { const token = performAsyncOperation(id.value) onInvalidate(() = > { // When the id changes or the listening stops // Cancel the asynchronous operation token.cancel() }) }) Copy the code
Case: To achieve the effect of user input “anti-shake”
<template>
<div>
<input type="text"
v-model="keyword">
</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const keyword = ref(' ')
const asyncPrint = val= > {
return setTimeout(() = > {
console.log('user input: ', val)
}, 1000)
}
watchEffect(
onInvalidate= > {
// If the interval entered by the user is less than one second, the timing will be cleared immediately and no result will be entered. Because of this, the user has realized the function of shaking, only when the user input time interval is greater than 1 second, do the printing
const timer = asyncPrint(keyword.value)
onInvalidate(() = > clearTimeout(timer))
console.log('keyword change: ', keyword.value)
},
// Flush: 'pre' watch() and watchEffect() run side effects before the DOM is mounted or updated, so the template reference has not yet been updated when the listener runs.
// Flush: defined with the 'post' option, which runs side effects after DOM updates, ensuring that template references are in sync with the DOM and refer to the correct elements.
{
flush: 'post' // Default 'pre', sync' sync', 'pre' component before update})return {
keyword
}
}
}
// Enable the user to enter "anti-shake" effect
</script>
Copy the code
watch
The Watch API is exactly equivalent to 2.x this.$watch (and the corresponding option in Watch). Watch needs to listen for specific data sources and perform side effects in callback functions. The default is lazy, meaning that callbacks are executed only when the source changes are being listened for.
The first argument received by watch() is called a “data source “, which can be:
- A getter function that returns any value
- A wrapper object (can be a REF or a Reactive wrapper object)
- An array containing both data sources
The second argument is the callback function. The callback function is triggered only when the data source changes:
-
Listening to a single data source
const state = reactive({count: 1}); // Listen to data defined by reactive. Changing count triggers a watch callback watch(() = >state.count,(newCount,oldCount) = >{ console.log('newCount:',newCount); console.log('oldCount:',oldCount); }) // listen for a ref const num = ref(0); watch(num,(newNum,oldNum) = >{ console.log('newNum:',newNum); console.log('oldNum:',oldNum); }) Copy the code
-
Listening for multiple data sources (arrays)
const state = reactive({count: 1}); const num = ref(0); // Listen on an array watch([() = >state.count,num],([newCount,newNum],[oldCount,oldNum]) = >{ console.log('new:',newCount,newNum); console.log('old:',oldCount,oldNum); }) Copy the code
-
Listen for complex nested objects
In our actual development, we see complex data everywhere, such as:
const state = reactive({ person: { name: 'Joe'.fav: ['handsome boy'.'beauty'.'music']}}); watch(() = > state.person, (newType, oldType) = > { console.log("The new value.", newType, "The old values.", oldType); }, { deep: true }, // Listen immediately ); Copy the code
You cannot listen for data changes without using the third parameter deep:true. As we mentioned earlier, watch is lazy by default, so when is it not lazy and the callback can be executed immediately? Set the third parameter to immediate: true
At the same time, Watch and watchEffect behave the same in stopping listening, clearing side effects (onInvalidate is passed in accordingly as the third argument to the callback), and so on.
<template>
<div>
<input type="text"
v-model="keyword">
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
setup() {
const keyword = ref(' ')
const asyncPrint = val= > {
return setTimeout(() = > {
console.log('user input: ', val)
})
}
watch(
keyword,
(newVal, oldVal, onCleanUp) = > {
const timer = asyncPrint(keyword)
onCleanUp(() = > clearTimeout(timer))
},
{
lazy: true // The default is false, that is, the initial listening callback is executed})return {
keyword
}
}
}
</script>
Copy the code
Lifecycle hook
A composite API corresponding to the 2.x release lifecycle
Create a new Test component/Components/test.vue
<template>
<div id="test">
<h3>{{a}}</h3>
<button @click="handleClick">To change the</button>
</div>
</template>
<script>
import {
ref,
onMounted,
onBeforeMount,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
export default {
// The lifecycle of the initialization data phase, between beforeCreate and Created
setup() {
const a = ref(0);
console.log("👌");
function handleClick() {
a.value += 1;
}
onBeforeMount(() = > {
console.log("Components before mounting");
});
onMounted(() = > {
console.log("DOM mount complete");
});
onBeforeUpdate(() = > {
console.log("Before DOM update".document.getElementById("test").innerHTML);
});
onUpdated(() = > {
console.log("DOM update completed".document.getElementById("test").innerHTML);
});
onBeforeUnmount(() = > {
console.log("Before instance uninstallation");
});
onUnmounted(() = > {
console.log("After instance uninstallation");
});
return{ a, handleClick }; }};</script>
Copy the code
Officially, you don’t have to understand everything right away, but it will become more valuable as you learn and use it.
Dependency injection
Provide and inject Provide dependency injection, which is similar to provide/inject of 2.x. Both can only be called from setup() of the current component
App. Vueprovide data sources
<template>
<div>
<Article></Article>
</div>
</template>
<script>
import {
ref,
provide
} from "vue";
import Article from "./components/Article";
export default {
setup() {
const articleList = ref([
{ id: 1.title: "Vue3.0 learning".author: "Little Marco" },
{ id: 2.title: "componsition api".author: "Yoda" },
{ id: 3.title: "Vue - the router's latest".author: "Vue official"}]);/* provide allows you to define properties with two arguments: the name of the property (type
) the value of the property */
provide("list",articleList);
return {
articleList
};
},
components: {
Article
}
};
</script>
Copy the code
Article. Vue injects data
<template>
<div>
{{articleList[0].title}}
</div>
</template>
<script>
import { inject } from "vue";
export default {
setup() {
const articleList = inject('list'[]);return{articleList}; }};</script>
Copy the code
The template references refs
When using composite apis, the concepts of Reactive refs and Template Refs are unified. To get a reference to an element or component instance within a template, declare a ref directly in setup() and return it
<template>
<div>
<div ref='wrap'>Hello vue3.0</div>
<Article ref='articleComp'></Article>
</div>
</template>
<script>
import {
ref,
onMounted,
provide
} from "vue";
import Article from "./components/Article";
export default {
setup() {
const isShow = ref(true);
const wrap = ref(null);
const articleComp = ref(null);
const articleList = ref([
{ id: 1.title: "Vue3.0 learning".author: "Little Marco" },
{ id: 2.title: "componsition api".author: "Yoda" },
{ id: 3.title: "Vue - the router's latest".author: "Vue official"}]);/* provide allows you to define properties with two arguments: the name of the property (type
) the value of the property */
provide("list", articleList);
onMounted(() = > {
console.log(wrap.value); // Get the div element
console.log(articleComp.value); // Get the article component instance object
});
return {
articleList,
wrap,
articleComp
};
},
components: {
Article
}
};
</script>
<style scoped>
</style>
Copy the code
Effect:
Component communication
- props
- $emit
- expose /ref
- attrs
- v-model
- provide/inject
- vuex
- mitt
props
/ / Parent. Vue
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
setup(){
// Create a responsive data
const msg1 = ref("This is the message of the cascade subcomponent 1")
const msg2 = reactive(["This is the message of the cascade subcomponent 2"])
return {
msg1
msg2
}
}
}
</script>
. / / the Child received vue
<script>
export default {
props: ["msg1"."msg2"].// If this line is not written, the following is not received
setup(props) {
console.log(props) // {msg1:" This is the message to child component 1", msg2:" This is the message to child component 2"}}},</script>
Copy the code
$emit
/ / Child. The vue
<template>
/ / write one
<button @click="$emit('myClick',123)">button</buttom>
</template>
<script>
export default {
emits: ['myClick']
//emits:{
//myClick:null
/ /}
}
</script>
/ / Parent. Vue response
<template>
<child @myClick="onMyClick"></child>
</template>
<script setup>
import child from "./child.vue"
const onMyClick = (msg) = > {
console.log(msg) // This is the message received by the parent component 123
}
</script>
Copy the code
Major change
Teleport
Teleport is like the “any door” in Doraemon. The function of any door is to Teleport people to another place in an instant. With this in mind, let’s see why we need to use the Teleport feature. Here’s a small example: Using a Dialog component in the Header child component makes it difficult to handle the positioning, z-index, and styling of nested components in similar situations that we often use in real development. Dialog should be an independent component from the user perception level, and the DOM structure should be completely stripped of the DOM mounted by the Vue top-level component. You can also use the value of the state (data or props) within the Vue component. Simply put, you want to continue to use dialogs inside the component, but you want to render DOM structures that are not nested inside the component’s DOM. This is where Teleport comes in. We can wrap the Dialog with
, which creates a portal that sends the contents of Dialog’s rendering to any specified location. Here’s a quick example of how Teleport can be used.
We want the DOM rendered by the Dialog to be sibling to the top-level component, defining a mount element in the index.html file:
<body>
<div id="app"></div>
<div id="dialog"></div>
</body>
Copy the code
Define a Dialog component dialog. vue, note that the to attribute is the same as the id selector above:
<template>
<teleport to="#dialog">
<! You want to continue using dialogs inside the component, but you also want to render DOM structures that are not nested inside the component's DOM. This is where Teleport comes in. We can wrap the Dialog with <Teleport>, which creates a portal to send the contents of the Dialog rendering to any specified location -->
<div class="dialog">
<div class="dialog_wrapper">
<div class="dialog_header">
<h3>I'm popbox {{count}}</h3>
</div>
</div>
</div>
</teleport>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
setup() {
const state = reactive({
count: 0,})return {
...toRefs(state),
}
},
}
</script>
<style lang="less" scoped></style>
Copy the code
Suspense
experimental
Suspense is an experimental new feature with an API that can change at any time. This announcement is made so that the community can provide feedback on the current implementation.
Do not use it in production environment
The suspense> component provides an alternative that allows the waiting process to be promoted into a component tree rather than in a single component.
The default slots are default and fallback. As the name implies, when a component to load does not meet its state,Suspense will fallback to fallback state until the component to load meets its condition.
Suspense.vue
Xx64 < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > </template> <template #fallback> <div class="loading"></div> </template> </Suspense> </template> <script> import { ref, defineAsyncComponent } from 'vue' export default { components: { MAsynComp: defineAsyncComponent(() => import('./AsynComp.vue')), }, setup() { const loadAsync = ref(false) const loadAsyncComponent = () => { loadAsync.value = true } return { loadAsync, loadAsyncComponent, } }, } </script> <style lang="less" scoped> button { padding: 12px 12px; background-color: #1890ff; outline: none; border: none; border-radius: 4px; color: #fff; cursor: pointer; } .loading { position: absolute; width: 36px; height: 36px; top: 50%; left: 50%; margin: -18px 0 0 -18px; background-image: url('.. /assets/loading.png'); background-size: 100%; Animation: Rotate 1.4s Linear infinite; } @keyframes rotate { from { transform: rotate(0); } to { transform: rotate(360deg); } } </style>Copy the code
AsynComp.vue
<template> <h1>this is async component</h1> </template> <script> import { setup } from 'vue' export default { name: 'AsyncComponent', async setup() { const sleep = (time) => { return new Promise((reslove, Reject) => {setTimeout(() => {reslove()}, time)})} await sleep(3000),} </script>Copy the code
Fragments
Multiple root components are allowed in Vue3.0 components, eliminating unnecessary div renderings
<template>
<div>The head</div>
<div>content</div>
</template>
Copy the code
The benefits of this:
- A lot fewer div’s that don’t make sense
- Horizontal recursion can be achieved, which is of great help in implementing the Tree component
emits
- emits can be an array or an object
- Triggers a custom event
- If emits is an array, this allows us to configure and validate events. The validation function should return a Boolean value indicating whether the event parameter is valid.
Emits.vue
$emit('submit',{username:'xiaomage',password:'123'})"> </button> </div> </template> <script> export default {// emits:['submit'],// can be array emits: {submit: payload => { if(payload.username && payload.password){ return true; }else{console.warn(' Invalid payload, please check submit event '); return false } } }, setup() { return {}; }}; </script> <style scoped> </style>Copy the code
App.vue
<Emits @submit="submitHandle"></Emits> <script> import Emits from "./components/Emits"; Export default{components:{Emits}, setup(){function submitHandle(payload) {console.warn(" custom event trigger ",payload); } return { } } } </script>Copy the code
Effect display:
The global Vue API is changed to the application instance
The above has been said, not to repeat one by one.
API can do Tree shakable optimization
In Vue2.0 there are many global apis that hang directly on the Vue constructor as static functions. You should have manually manipulated the DOM and encountered the following pattern. If we don’t use them in code, we form what we call “dead code”. This kind of global API creates “dead code” that cannot be “dead code removed” using Webapck’s tree-shaking.
import Vue from 'vue'
Vue.nextTick(() = >{
// Something DOM related
})
Copy the code
As a result, Vue3.0 has made a change to separate them into separate functions so that tree shaker optimization of the packaging tool can eliminate these “dead code”. The global API can now only be accessed as named exports of ES module builds. For example, our previous fragment should now look like this
import {nextTick} from 'vue'
nextTick(() = >{
// Something DOM related
})
Copy the code
Affected apis
These global apis in Vue2. X are affected by this change:
- Vue.nextTick
- Ue. Observable (replaced by ue. Reactive)
- Vue.version
- Vue.compile(fully built only)
- Vue.set(Compatible version only)
- Vue.delete(Compatible version only)
TreeShaking.vue
<template>
<div >
<hr />Tree shaking optimizes unnecessary code that has not been introduced<div id='name'>Mr Ma</div>
<h3 ref='myMsg'>{{msg}}</h3>
<button @click="changeMsg('hai! ')">change</button>
</div>
</template>
<script>
import { ref, nextTick } from "vue";
export default {
setup() {
const msg = ref("hello!");
const myMsg = ref(null);
async function changeMsg(newV) {
msg.value = newV;
// console.log(myMsg.value.innerText); // Get the DOM directly as before
NextTick returns a Promise object
await nextTick();
console.log(myMsg.value.innerText);
}
return{ msg, myMsg, changeMsg }; }};</script>
Copy the code
Slot Name Slot syntax
In Vue2. X, the named slot is written:
<! -- Subcomponent: -->
<slot name="title"></slot>
Copy the code
Used in the parent component:
<template slot="title">
<h1>Song: "The Lonely One"</h1>
<template>
Copy the code
If we want to bind data to a slot, we can use a scoped slot as follows:
// subcomponent <slot name="content" :data="data"></slot> export default {data(){return{data:[" Go through people come and go "," don't like to enjoy "," company is the most love "] }}}Copy the code
<! -- used in parent component -->
<template slot="content" slot-scope="scoped">
<div v-for="item in scoped.data">{{item}}</div>
<template>
Copy the code
In vue2. x, named slot and scoped slot are implemented using slot and slot-scope respectively. In Vue3.0, slot and slot-scope are combined and approved. The v – slot Vue3.0:
<! -- used in parent component -->
<template v-slot:content="scoped">
<div v-for="item in scoped.data">{{item}}</div>
</template>
<! -->
<template #content="{data}">
<div v-for="item in data">{{item}}</div>
</template>
Copy the code
V-model usage on components
After Vue 2.0 was released, developers using v-model directives had to use prop as Value. If a developer needs to use another prop for a different purpose, they have to use V-bind.sync. In addition, this hard-coded relationship between the V-Model and value raises the question of how to handle native and custom elements.
In Vue 2.2, we introduced the Model component option, which allows components to customize prop and events for v-Models. However, this still allows only one Model to be used on the component.
In Vue 3, the API for two-way data binding has been standardized, reducing developer confusion when using V-Model directives and allowing more flexibility when using V-Model directives.
2. X syntax
In 2.x, using v-Models on components is equivalent to binding value prop and input events:
<ChildComponent v-model="pageTitle" />
<! -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
Copy the code
To change the property or event name to something else, add the Model option to the ChildComponent component:
<! -- ParentComponent.vue -->
<ChildComponent v-model="pageTitle" />
Copy the code
// ChildComponent.vue
export default {
model: {
prop: 'title'.event: 'change'
},
props: {
// This will allow the 'value' attribute to be used for other purposes
value: String.// Use 'title' instead of 'value' as model prop
title: {
type: String.default: 'Default title'}}}Copy the code
So, in this example, v-model is abbreviated as follows:
<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
Copy the code
usev-bind.sync
In some cases, we may need to “bidirectional bind” a prop (except for the previous v-model binding of the prop). To do this, we recommend throwing events using Update :myPropName. For example, for the ChildComponent with a title prop in the previous example, we could communicate the intent to assign a new value to the parent as follows:
this.$emit('update:title', newValue)
Copy the code
The parent can listen for this event and update the local data property if needed. Such as:
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Copy the code
For convenience, we can use the.sync modifier to abbreviate, as follows:
<ChildComponent :title.sync="pageTitle" />
Copy the code
3. X syntax
In 3.x, a V-Model on a custom component is equivalent to passing a modelValue prop and receiving an Update :modelValue event thrown:
<ChildComponent v-model="pageTitle" />
<! -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
Copy the code
Render function API changed
h
It is now imported globally instead of being passed as a parameter to the render function- Render function parameters are more consistent between stateful components and function components
- Vnode is now a flat prop structure
The Render function will automatically accept the h function (alias for createElement) as an argument
//vue2.x
export default{
render(h){
return h('div')}}/ / vue3 rendering
import { h } from 'vue'
export default {
render() {
return h('div')}}Copy the code
Here’s an example:
<template>
<div>
<RenderComp v-model='title'>
<template v-slot:default>
<! -- Default slot -->The head</template>
<template v-slot:content>
<! -- named slot -->content</template>
</RenderComp>
</div>
</template>
<script>
import {
ref,
h
} from "vue";
export default {
components: {
RenderComp: {
props: {
modelValue: {
type: String.default: ' '}},setup(props,{attrs,slots,emit}) {
$scopedSlots was used to get the corresponding slot
console.log(slots.default()); // Get the default slot
console.log(slots.content()); // Get the slot with the name content
function changeTitle(newV) {
emit('update:modelValue'.'Hahaha');
}
return () = > h("div", {}, [h("div", {
onClick:changeTitle,
},[
'Render function API:${props.modelValue}`, slots.default(), slots.content() ])]); }}},setup(props) {
const title = ref("Two-way data binding");
return{ title }; }};</script>
Copy the code
Also, we demonstrate that the $scopedSlotsproperty has been removed and all slots are exposed as a function of $slots
Create functional components using normal functions
- In 3.x, the performance gain for functional component 2.x is negligible, so we recommend using only stateful components
- Functional components can only use receive
props
å’Œcontext
Normal function creation (that is:slots
.attrs
.emit
). - Major changes:
functional
Attribute in single file Component (SFC)<template>
Have been removed - Major changes:
{ functional: true }
The option to create a component by function has beenHas been removed
In VUe2.0, functional components serve two main purposes:
- Performance optimization improves because they initialize faster than stateful components
- Multiple root nodes can be returned
However, in Vue 3, the performance of stateful components has improved to a negligible level. In addition, stateful components now include the ability to return multiple root nodes.
Thus, the only use cases left for functional components are simple components, such as those that create dynamic titles. Otherwise, it is recommended that you use stateful components as usual.
Bottom line: Except for special cases, the website still recommends using stateful components
Functional.vue
import { h } from 'vue'
const DynamicHeading = (props, context) = > {
return h(`h${props.level}`, context.attrs, context.slots)
}
DynamicHeading.props = ['level']
export default DynamicHeading
Copy the code
<Functional level='3'>Dynamic title</Functional>
Copy the code
You can pass in different levels to customize different H series titles.
Changes to asynchronous components
- new
defineAsyncComponent
Helper method, which displays the definition of asynchronous components componnet
I’ll call itloader
- The loader function is not accepted by itself
resolve
andreject
Parameter, must return a Promise
2.x
Previously, asynchronous components were created by defining the component as a function that returns a promise, for example:
const asyncPage = () = > import('./NextPage.vue')
Copy the code
For higher-level component syntax with options:
const asyncPage = {
component: () = > import('./NextPage.vue'),
delay: 200.timeout: 3000.error: ErrorComponent,
loading: LoadingComponent
}
Copy the code
3.x
In VUE3, since functional components are defined as pure functions, components need to be explicitly defined by wrapping asynchronous component definitions in the new defineAsyncComponent helper
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// Asynchronous components with no options
const asyncPage = defineAsyncComponent(() = > import('./NextPage.vue'))
// Asynchronous components with options
const asyncPageWithOptions = defineAsyncComponent({
loader: () = > import('./NextPage.vue'),
delay: 200.timeout: 3000.errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
Copy the code
Custom instruction
The API has been renamed to better align with the component lifecycle
- The bind – beforeMount
- He inserted – mounted
- BeforeUpdate: new!!! This is called before the element itself is updated, much like a component lifecycle hook
- Update → Remove! There are too many similarities to update, so this is redundant, please use it instead
updated
- ComponentUpdated – updated
- **beforeUnmount **
The new
Similar to a component lifecycle hook, it is called before an element is unloaded. - unbind -> unmounted
Here’s an example:
main.js
const app = createApp(App);
// Create a custom directive
app.directive('highlight', {Directives also have a set of lifecycle hooks
// 1. Called before the parent component of the bound element is mounted
beforeMount(el,binding,vnode){ el.style.background = binding.value; }})Copy the code
App.vue
<p v-highlight="'red'">Custom instruction</p>
Copy the code
Animation Transion changes
- v-enter->v-enter-from
- v-leave->v-leave-from
Vue2. X version
Remove the API
keyCode
Support asv-on
The modifier
Off and $once instance methods- filter
2.x, which supports keyCodes as a way to modify V-on methods
<! -- Keycode version -->
<input v-on:keyup.13="submit" />
<! -- Alias version -->
<input v-on:keyup.enter="submit" />
Copy the code
vue3.x
It is recommended to use the kebab-cased (dash) case name for any key to be used as a modifier.
<! -- Vue 3 uses keystroke modifier on V-ON -->
<input v-on:keyup.delete="confirmDelete" />
Copy the code
Therefore, this means that config.keycodes are now deprecated and no longer supported.
The $ON, $OFF, and $once instance methods have been removed, and the application instance no longer implements the event-triggering interface.
Filters have been removed from Vue 3.0 and are no longer supported. Instead, we recommend replacing them with method calls or computed properties.