Vue2 imports the entire vue each time, as in the main.js file of vue2:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount('#app')
Copy the code
Obviously, it is impossible to use all the APIS of Vue in the project, so many modules are actually useless. In Vue3, many apis are exposed for developers to use. We can import the required APIS from Vue according to our own needs. For example, the code in main.js:
import { createApp } from 'vue';
import App from './App.vue'
createApp(App).mount('#app')
Copy the code
Using the import/export syntax of import and export, the function of packing modules on demand is realized. The file size after the project is packaged is significantly smaller, which is why we need to have a detailed understanding of Vue3 API in this article.
1. setup
The setup function is also the entry function of the Compsition API. Our variables and methods are defined in this function.
< the template > < div id = "app" > < p > {{number}} < / p > < button @ click = "add" > add < / button > < / div > < / template > < script > / / 1. Import {ref} from 'vue' export default {name: 'App', setup() {// 2. Number let number = ref(0) // 3. Function add() {// number is wrapped in the.value function. Value ++} // 4. Return number and add for template with return {number, add}} </script>Copy the code
The ref function is used in the above code, which will be explained in detail below. Here you only need to understand that its function is to wrap a responsive data, and you can think of the variables wrapped by the REF function as the variables in Vue2 data, which is easy to implement a button increment function.
In Vue2, we access variables in data or props using something like this.number, but it’s important to note that in setup, this refers to undefined, This means that you can no longer use this to fetch variables as Vue2 did.
So how do I get the data in props?
The setup function also has two parameters: props and context. The former holds the names of the parameters that are allowed to be passed from the current component and the corresponding values. The latter is a context object from which you can access attr, EMIT, slots. Emit is the familiar Vue2 method for communicating with the parent component and can be called directly.
The first parameter of the setup function is props
setup(props,context){}
Copy the code
The first parameter props:
- Props is an object that contains all the data that the parent component passes to the child component.
- Use props to receive in the child component.
- The object that contains all the properties passed in by the configuration declaration. That is, if you want to output the value passed by the parent component to the child component as props. You need to use props for the receive configuration. The props: {… }, if you are not using props to receive configuration, the output value is undefined.
<template>
<div class="box" @click="sonHander">
我是子组件中的数据
</div>
</template>
<script>
export default {
//未进行接收
// props:{
// mytitle:{
// type: Object
// }
// },
setup(props, context) {
const sonHander = function(){
context.emit('sonclick', '子组件传递给父组件');
}
console.log(props.mytitle);
return {sonHander}
}
};
</script>
Copy the code
<template> <div class="box" @click="sonHander"> </div> </template> <script> export default {// not received // props:{ // mytitle:{ // type: Object //} //}, setup(props, context) {const sonHander = function(){context.emit('sonclick', 'child to parent '); } console.log(props.mytitle); Return {sonHander}}}; </script>Copy the code
Why is the output of props. Mytitle undefined? Because we didn't use props for the receive configuration. Props :{mytitle:{type:Object}} If we add a receive configuration, we will receive data passed from the parent componentCopy the code
1.2 Description of context
The second argument, context, is an object.
- There is attrs(the object that gets all the attributes on the current tag), but that attribute is all the objects that are not declared to be received in props.
- Attrs = undefined if you use props to get the value, and you declare the value you want to get in props, attrs is undefined.
- Note: attrs gets a value that does not need to be accepted declared in props. The first parameter gets a value that the props declaration accepts.
- It contains emit event distribution, which is required to be passed to the parent component.
- There are slots in it.
<template> <div class="box" @click="sonHander"> </div> </template> <script> export default {// not to accept props: {mytitle: {type: Object,},}, setup(props, context) {// Output title: the value passed by the parent component console.log(props. Mytitle); // Output someone else's title: Use context to get the value, don't need to use props to receive console.log(context.attrs.othertitle); // output undefined, because context doesn't need props to receive console.log(context.attrs.mytitle); Const sonHander = function () {context.emit("sonclick", "child to parent "); }; return { sonHander }; }}; </script>Copy the code
1.3 Child Components send events to parent components
<template> <div class="box" @click="sonHander"> </div> </template> <script> export default {props, Context) {const sonHander = function () {context.emit("sonclick", "child to parent "); }; return { sonHander }; }}; </script>Copy the code
1.4 Optimized event Dispatch
We know that the second context parameter is an object, and the object has three attributes, attrs,slots, and emit.
<template> <div class="box" @click="sonHander"> </div> </template> <script> export default {props, Const sonHander = function () {emit("sonclick", "child component to parent component "); }; return { sonHander }; }}; </script> <style> </style>Copy the code
1.5 Get the value passed by the parent component
We’ll get the value using the props parameter and attrs.
<template> <div class="box" @click="sonHander"> </div> <h2> Use the props declaration to receive: {{props. Mytitle}}</h2> <h2> Use the attrs parameter: {{attrs.othertitle}}</h2> </template> <script> export default {// no props: {mytitle: {type: Object,},}, setup(props, {emit, attrs}) {const sonHander = function () {emit ("sonclick", "child to parent "); }; return { sonHander, attrs, props }; }}; </script>Copy the code
2. Life cycle
Vue2 has beforeCreate, Created, beforeMount, Mounted, beforeUpdate and other life cycle functions. In Vue3, these life cycle parts change and the way they are called is also changed. So let’s put a little bit of a change diagram to get a sense of it.
Vue2 | Vue3 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestory | onBeforeUnmount |
destoryed | onUnmounted |
2.1 Create hooks for composite apis
For Vue3 lifecycle hooks using the composite API, replace beforecate and Created with the setup() method. This means that any code you put in these methods is now only in the Setup methods.
// AP import {ref} from 'vue' export default {setup() {const val = ref('hello') console.log('Value of val is: ' + val.value) return { val } } }Copy the code
2.2 beforeMount () and onBeforeMount ()
Called before the component DOM is actually rendered and installed. In this step, the root element does not yet exist. In the options API, you can access it using this.$els. In the composition API, in order to do this, ref must be used on the root element.
<template> <div ref='root'> Hello World </div> </template> import {ref, onBeforeMount } from 'vue' export default { setup() { const root = ref(null) onBeforeMount(() => { console.log(root.value) }) return { root } } }Copy the code
Because app.$el has not yet been created, the output will be undefined.
2.3 mounted () and onMounted ()
Called after the first rendering of the component, this element is now available, allowing direct DOM access. Similarly, in the option API, we can use this.$el to access our DOM, and in the composite API, we need to use ref to access the DOM in the Vue lifecycle hook.
import { ref, OnMounted} from 'vue' export default {setup() {/* / const root = ref(null) onMounted(() => { console.log(root.value) }) return { root } } }Copy the code
2.4 beforeUpdate () and onBeforeUpdate ()
Called when data is updated and occurs before the virtual DOM is patched. This is a good place to access the existing DOM before updating, such as manually removing event listeners that have been added.
BeforeUpdate is useful for tracking the number of edits to components and even the actions that create undo functionality.
2.5 updated () and onUpdated ()
When the DOM is updated, the updated method is called.
<template>
<div>
<p>{{val}} | edited {{ count }} times</p>
<button @click='val = Math.random(0, 100)'>Click to Change</button>
</div>
</template>
<script>
import { onBeforeUpdate,onUpdated, ref} from 'vue'
export default {
setup () {
const count = ref(0)
const val = ref(0)
onBeforeUpdate(() => {
count.value++;
console.log("beforeUpdate");
})
onUpdated(() => {
console.log("updated() val: " + val.value)
})
return {
count, val
}
}
};
</script>
Copy the code
These methods are useful, but for more scenarios, we need to use the Watch method to detect these data changes. Watch works because it gives the old and new values of the changed data.
Another option is to use computed attributes to change state based on the element.
2.6 beforeUnmount () and onBeforeUnmounted ()
Called before the component instance is unloaded. At this stage, the instance is still perfectly normal.
An example of deleting an event listener in a composite API is shown below.
import { onMounted, onBeforeUnmount } from 'vue' export default { setup () { const someMethod = () => { // do smth } onMounted(() => { console.log('mount') window.addEventListener('resize', someMethod); }) onBeforeUnmount(() => { console.log('unmount') window.removeEventListener('resize', someMethod); }}})Copy the code
The reality is that in Vite, VUE-CLI, or any development environment that supports hot overloading, some components will uninstall and install themselves when the code is updated.
2.7 unmounted () and onUnmounted ()
Called after the component instance is unloaded. When this hook is called, all directives of the component instance are unbound, all event listeners are removed, and all child component instances are unloaded.
Import {onUnmounted} from 'vue' export default {setup () {/* onUnmounted() => {console.log('unmounted') }}})Copy the code
2.8 activated () and onActivated ()
Called when activated by a component cached by keep-alive.
For example, if we use the Keep-alive component to manage different TAB views, the current TAB will run the Activated hook every time we switch between tabs.
Suppose we use the keep-alive wrapper for the following dynamic components.
<template> <div> <span @click='tabName = "Tab1"'>Tab 1 </span> <span @click='tabName = "Tab2"'>Tab 2</span> <keep-alive> <component :is='tabName' class='tab-area'/> </keep-alive> </div> </template> <script> import Tab1 from './Tab1.vue' import Tab2 from './Tab2.vue' import { ref } from 'vue' export default { components: {Tab1, Tab2}, setup () {/* setup API */ const tabName = ref('Tab1') return {tabName}} </script>Copy the code
Inside the Tab1.vue component, we can access the Activated hook like this.
<template> <div> <h2>Tab 1</h2> <input type='text' placeholder='this content will persist! '/> </div> </template> <script> import { onActivated } from 'vue' export default { setup() { onActivated(() => { console.log('Tab 1 Activated') }) } } </script>Copy the code
2.9 deactivated () and onDeactivated ()
Called when a component cached by keep-alive is disabled.
This hook is useful in use cases such as saving user data and triggering animations when a particular view loses focus.
import { onActivated, onDeactivated } from 'vue'
export default {
setup() {
onActivated(() => {
console.log('Tab 1 Activated')
})
onDeactivated(() => {
console.log('Tab 1 Deactivated')
})
}
}
Copy the code
3. reactive
The Reactive method is used to create a reactive data object.
The usage is as simple as passing in the data as an argument, as shown below
<template> <div id="app"> <! Count --> {{state-count}} </div> </template> <script> // 1. Reactive import {reactive} from 'vue' export default {name: 'App', setup() {// 2. Const state = reactive({count: 3}) // 3. Return state for template to use return {state}} </script>Copy the code
4. ref
When we introduced the setup function, we used the ref function to wrap a reactive data object. It looks exactly like reactive, and it does, because ref wraps an object in reactive. Then we pass the value to the value property in the object, which explains why we need to add.value every time we access it
Reactive ({value: obj}) reactive({value: obj})
So let’s write a little bit of code to look at that
<script> import { ref, reactive } from "vue"; export default { setup() { const obj = { count: 3 }; const state1 = ref(obj); const state2 = reactive(obj); console.log(state1.value); console.log(state2); }}; </script>Copy the code
Note: The.value is required to access the ref-wrapped object in the setup function, not in the template template, because at compile time, It automatically recognizes that it’s ref wrapped so how do we choose ref and Reactive?
Advice:
- Values of primitive types (String, Nmuber, Boolean, and so on) or single-valued objects (similar to objects with a single attribute value like {count: 3}) use ref.
- Reference type values (Object, Array) Use Reactive.
5. toRef
ToRef is to convert a value in an object into responsive data, which receives two parameters, the first parameter is obJ object; The second parameter is the name of the property in the object
The code is as follows:
<script> // 1. Import toRef import {toRef} from "vue"; export default { setup() { const obj = { count: 3 }; Const state = toRef(obj, "count"); // 3. Return toRef wrapped data object for Template to use return {state}; }}; </script>Copy the code
But on the surface it looks like the toRef API is very useless, because this function can also be implemented with ref, as shown below
Ref import {ref} from 'vue' export default {setup() {const obj = {count: 3} // 2. Const state = ref(obj.count) // 3. Return the ref wrapped data object for template using return {state}}} </script>Copy the code
At first glance, this may seem true, but there is a difference between the two. We can compare this with an example. The code is as follows
< the template > < p > {{state1}} < / p > < button @ click = "add1" > add < / button > < p > {{state2}} < / p > < button @ click = "add2" > add < / button > </template> <script> import { ref, toRef } from "vue"; export default { setup() { const obj = { count: 3 }; const state1 = ref(obj.count); const state2 = toRef(obj, "count"); function add1() { state1.value++; Console. log(" original value: ", obj); Console. log(" Responsive data object: ", state1); } function add2() { state2.value++; Console. log(" original value: ", obj); Console. log(" Responsive data object: ", state2); } return { state1, state2, add1, add2 }; }}; </script>Copy the code
We use ref and toRef respectively to convert count in obj to reactive, and declare two methods to increase count, respectively. After each increment, we print the original value obj and the wrapped reactive data object, and also look at the view changes. ref:
- As you can see, after the +1 operation on the value of the responsive data, the view changes, the original value remains unchanged, and the value of the responsive data object also changes. This indicates that ref is a copy of the original data, and the original value will not be affected. Meanwhile, the view will be updated synchronously after the value of the responsive data object changes.
ToRef:
- As you can see, after the +1 operation on the value of the reactive data, the view does not change. The original value is changed, and so is the value of the reactive data object. This indicates that toRef is a reference to the original data and will affect the original value, but will the view be updated after the value of the reactive data object changes.
Conclusion:
- Ref is a copy of the incoming data; ToRef is a reference to incoming data
- Changing the value of ref updates the view; A toRef value change does not update the view
6. toRefs
Now that you know about toRef, it’s easy to understand toRefs, which converts the values of all the attributes in the passed object into a responsive data object. This function supports one parameter, an OBJ object.
Let’s take a look at the basic uses
<script> // 1. ToRefs import {toRefs} from "vue"; Export default {setup() {const obj = {name: "front-end impression ", age: 22, gender: 0,}; Const state = toRefs(obj); Console. log(state); }}; </script>Copy the code
The print result is as follows:
It returns an object containing each wrapped reactive data object.
7. toRaw
The toRaw method is used to retrieve raw data from a REF or Reactive object.
Let’s start with a piece of code
< the template > < p > {{state. The name}} < / p > < p > {{state. The age}} < / p > < button @ click = "change" > change < / button > < / template > < script > import { reactive } from "vue"; Export default {setup() {const obj = {name: "front-end impression ", age: 22,}; const state = reactive(obj); function change() { state.age = 90; console.log(obj); // Print raw data obj console.log(state); // Print reactive object} return {state, change}; }}; </script>Copy the code
When we change the data in the Reactive object, we see that the value of the original data OBj and the object wrapped by Reactive have changed, so that we can see that the two are a reference.
So now we’re thinking, what happens if we just change the value of obj, the original value? The answer is: The value of reactive changes, but the view does not update.
Thus, when we want to modify the data but do not want the view to update, we can choose to directly modify the value of the original data, so we need to obtain the original data first, we can use the toRaw method provided by Vue3
ToRaw receives a parameter, a REF object or a Reactive object
<script> import { reactive, toRaw } from "vue"; Export default {setup() {const obj = {name: "front-end impression ", age: 22,}; const state = reactive(obj); const raw = toRaw(state); console.log(obj === raw); // true }, }; </script>Copy the code
This code demonstrates that the toRaw method fetches raw data from reactive objects, so it is easy to do performance optimizations by modifying the raw data without updating the view. Note: As a side note, when the toRaw method receives a ref object, it needs to add.value to get the original data object.
8. provide && inject
Provide and inject the same functions as those in Vue2, but in Vue3, you need to import them manually from vUE.
Here’s a quick explanation of how these two methods work:
- Provide: Pass data to child and descendant components. The first parameter is key, which is the name of the data. The second argument is value, the value of the data
- Inject: Receives data passed by parent or ancestor components. Receives a parameter key, which is the name of the data passed by the parent or ancestor component
Assume that there are three components: A.vue, B.vue, and C.vue, where B.vue is a sub-component of A.vue and C.vue is a sub-component of B. Vue
// A.vue <script> import { provide } from "vue"; Export default {setup() {const obj = {name: "front-end impression ", age: 22,}; // Provide data named info to child and descendant components ("info", obj); }}; </script> // B.vue <script> import { inject } from "vue"; Export default {setup() {// Receive data inject("info"); // {name: 'front-end impression ', age: 22}},}; </script> // C.vue <script> import { inject } from "vue"; Export default {setup() {// Receive data inject("info"); // {name: 'front-end impression ', age: 22}},}; </script>Copy the code
9. watch && watchEffect
Both Watch and watchEffect are used to monitor a change in data to perform a specified action, but there are differences in their usage. Watch: watch(source, cb, [options])
- Source: Can be an expression or a function that specifies the dependent object to listen on
- Cb: callback function executed after the dependent object changes
- Options: Optional. You can configure the following properties: immediate (triggers the callback function immediately) and deep (deep listening)
When listening on a ref type:
<script> import { ref, watch } from "vue"; export default { setup() { const state = ref(0); Watch (state, (newValue, oldValue) => {console.log(' original value is ${oldValue} '); Console. log(' newValue ${newValue} '); /* Prints the result after 1 second: original value is 0 new value is 1 */}); SetTimeout (() => {state.value++; }, 1000); }}; </script>Copy the code
When listening to reactive:
<script> import { reactive, watch } from "vue"; export default { setup() { const state = reactive({ count: 0 }); Watch (() => state.count, (newValue, oldValue) => {console.log(' original value is ${oldValue} '); Console. log(' newValue ${newValue} '); /* Prints the result after 1 second: original value is 0 new value is 1 */}); SetTimeout (() => {state.count++; }, 1000); }}; </script>Copy the code
When listening for more than one value at a time:
<script> import { reactive, watch } from "vue"; export default { setup() { const state = reactive({ count: 0, name: "zs" }); watch( [() => state.count, () => state.name], ([newCount, newName], [oldvCount, oldvName]) => { console.log(oldvCount); // Old count value console.log(newCount); // The new count value console.log(oldName); // Old name value console.log(newvName); // New name value}); setTimeout(() => { state.count++; state.name = "ls"; }, 1000); }}; </script>Copy the code
Since the first parameter of the watch method has been specified, the callback function in the second parameter is not executed when the component is initialized. If we want the component to be initialized first, we can set the third parameter object to immediate: true
For example, if the data we are listening to is nested in multiple layers, the change of the deep data will not trigger the callback. If we want it to listen on the deep data, we can set deep: true in the third parameter object
Add: The watch method returns a stop method that you can execute if you want to stop listening
Next, let’s talk about watchEffect, which differs from Watch in the following points:
- There is no need to pass in dependencies manually
- A callback function is executed for each initialization to automatically retrieve dependencies
- You can’t get the original value, you can only get the changed value
Let’s see how this works:
<script> import { reactive, watchEffect } from "vue"; export default { setup() { const state = reactive({ count: 0, name: "zs" }); watchEffect(() => { console.log(state.count); console.log(state.name); /* Prints when initializing: 0 zs prints after 1 second: 1 ls */}); setTimeout(() => { state.count++; state.name = "ls"; }, 1000); }}; </script>Copy the code
As you can see from the code above, instead of passing a dependency to the watch method first, we specify a callback function directly. When the component is initialized, the callback function is executed once and the data to be detected is automatically retrieved as state.count and state.name. Based on the above characteristics, we can choose which listener to use.
10. computed
Computed (computed properties) passes in a getter function that returns a ref object that cannot be manually modified by default, and is used much differently than VUE 2.0.
Computed is used by default
<template> <div class="home"> <p> <button type="button" @click="changeAge(-1)">-</button> {{ age }} <button type="button" @click="changeAge(1)"> </button> <p> <p> {{ year }}</p> </div> </template> <script> import { computed, ref } from "vue"; export default { name: "Home", setup() { const age = ref(19); function changeAge(value) { age.value += value; } const year = computed(() => { return 2020 - age.value; }); return { year, age, changeAge, }; }}; </script>Copy the code
The computed getter and setter
<template> <div class="home"> <p> <button type="button" @click="changeAge(-1)">-</button> {{ age }} <button type="button" @click="changeAge(1)"> </button> <p> <p> <button type="button" @click="changeYear(-1)">-</button> {{ year }} <button type="button" @click="changeYear(1)">+</button> </p> </div> </template> <script> import { computed, ref } from "vue"; export default { name: "Home", components: {}, setup() { const age = ref(19); function changeAge(value) { age.value += value; } const year = computed({ get() { return 2020 - age.value; }, set(val) { age.value = 2020 - val; }}); function changeYear(value) { year.value = year.value + value; } return { year, age, changeYear, changeAge, }; }}; </script>Copy the code