Vue3 documentation: v3.cn.vuejs.org

Composition API, which literally means Composition API, was created to enable function-based logical reuse mechanisms. The main idea is that we define them as JavaScript variables returned from the new setup function, rather than defining component functions (such as state, Methods, computed, and so on) as object properties.

Note:

Vue3.0 scaffold creation (according to individual needs) :

① Create project: vue create Project name

(2) Choose whether to use Taobao mirror (recommended, faster in China) :

 Your connection to the default npm registry seems to be slow.
 Use https://registry.npm.taobao.org for faster installation? (Y/n) 
Copy the code

③ Select the version to create the project:

④ Plug-in options

⑤ Select the VUE version

⑥ Class style syntax

⑦ Compile JSX with TypeScript and Babel (I chose no)

⑧ Select a routing mode

⑨ Select the CSS preprocessor syntax (recommended to use DARt-sass).

⑩ESLint Syntax configuration. The first one is selected by default

Tick ESlint features and functions

Depending on whether the configuration file is stored separately or directly in a package.json file. I’m going to put it in a separate file.

Whether to save the configuration

If you have both NPM and YARN installed, we do a package management program. Then we ask you one last time to choose which one to use for the download. NPM is recommended.


The basic template in VUe3:

<! Vue2 component templates must have a pair of tags, but vue3 component templates do not --><template>

</template>

<script lang="ts">
// defineComponent, which defines a component and can be passed a configuration object internally
import { defineComponent } from "vue";

export default defineComponent({
    name: "HelloWorld"});</script>

<style scoped>
</style>
Copy the code

Note: Custom Eslint code checks

/* * @Author: * @Date: * @LastEditors: * @LastEditTime: * @FilePath: * @Description: Code review https://blog.csdn.net/fu983531588/article/details/109333898 * * parameter interpretation The first parameter: "Off" or 0- turns off rule "WARN" or 1- turns the rule on as a warning (does not affect exit code) "Error" or 2- turns the rule on as an error (exit code will be 1) */
module.exports = {
    root: true.env: {
        node: true
    },
    extends: [
        'plugin:vue/vue3-essential'.'eslint:recommended'.'@vue/typescript/recommended'].parserOptions: {
        ecmaVersion: 2020
    },
    rules: {
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off'.'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'.'block-scoped-var': 'off'.// Use var in block statements
        'consistent-this': ['error'.'that']./ / this alias
        'default-case': 'error'.// The switch statement must end with default
        'eqeqeq': 'error'.// Use === and! = =
        'indent': ['error'.4].// Indent style
        'no-const-assign': 'error'.// Disallow changes to const variables
        /** * always (default) : semicolon is required at the end of a statement
        'semi': ['error'.'always'].// The statement enforces the semicolon ending

    },
    overrides: [{files: [
                '**/__tests__/*.{j,t}s? (x)'.'**/tests/unit/**/*.spec.{j,t}s? (x)'].env: {
                jest: true}}}]Copy the code

First, the principle of the response of Vue3

Reflect: Performs a specific operation on the corresponding property of the proscribed object dynamically.

Documents:

Developer.mozilla.org/zh-CN/docs/…

Developer.mozilla.org/zh-CN/docs/…

new Proxy(data, {
	// Intercepts read property values
    get (target, prop) {
    	return Reflect.get(target, prop)
    },
    // Intercepts set property values or adds new properties
    set (target, prop, value) {
    	return Reflect.set(target, prop, value)
    },
    // Intercept the delete attribute
    deleteProperty (target, prop) {
    	return Reflect.deleteProperty(target, prop)
    }
})

proxy.name = 'tom'   
Copy the code
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>The Proxy to Reflect</title>
</head>
<body>
    <script>
        const user = {
            name: "John".age: 12
        };
        /* proxyUser is the proxy object, user is the proxy object, all operations are performed on the internal properties of the proxy object */
        const proxyUser = new Proxy(user, {

            get(target, prop) {
                console.log('hijacked the get ()', prop)
                // Reflect the object
                return Reflect.get(target, prop)
            },

            set(target, prop, val) {
                console.log('hijacked set ()', prop, val)
                return Reflect.set(target, prop, val); / / (2)
            },

            deleteProperty(target, prop) {
                console.log('Hijack delete property', prop)
                return Reflect.deleteProperty(target, prop)
            }
        });
        // Read the property value
        console.log(proxyUser === user)
        console.log(proxyUser.name, proxyUser.age)
        // Set the property value (modifying a value on the target object via the proxy object)
        proxyUser.name = 'bob'
        proxyUser.age = 13
        console.log(user)
        // Add attributes
        proxyUser.sex = 'male'
        console.log(user)
        // Delete the attribute
        delete proxyUser.sex
        console.log(user)
    </script>
</body>
</html>
Copy the code

Use of setup

Note:

The setup() function is a special addition to Vue3 and can be understood as an entry to the Composition Api.

Setup is called before component creation, that is, before beforeCreate, created, so there is no this;

The setup function is called before the component is created, so the component instance is not created when setup is executed. So in the setup function, we’re going to have no way to get this;

(4) Setup is a function that is executed only once during initialization.

If the function returns an object, an object attribute or a method, the HTML template can be directly used;

⑥ Do not mix the methods: You can access attributes and methods provided by setup, but you can not access data and methods in the Setup method;

Setup cannot be an async function because the return value is no longer a return object, but a promise, and the template does not see attribute data in the return object.

(8) Do not mix the methods: You can access properties and methods provided by setup, but you cannot access data and methods in setup;

⑨ Setup cannot be an async function: since the return value is no longer a return object, but a promise, the template cannot see the property data in the return object.

<template>
    <div>
        {{data.count}} <br />
        {{data.double}} <br />
        <button @click="fun">increase</button>
    </div>
</template>
<script>
If you want to define objects, you need to introduce reactive, and if you want to use reactive properties, you need to introduce */
import { computed, reactive } from "vue"
export default {
    setup() {
        const data = reactive({
            count: 1.// If the following section is a single line of code, return is not allowed
            double: computed(() = > data.count * 2)});function fun() {
            data.count++
        };
        // Return a method or variable that is used in a template. (data is an attribute. It can be written as :data :data for short)
        return { data, fun }
    }
}
</script>
Copy the code

1, forward transmission value

1) In the parent component

<template>
    <div>
        <SubComp num="22" />
    </div>
</template>
<script>

import SubComp from "Child component path";
export default {
    components:{
        SubComp
    },
}
</script>
Copy the code

2) In sub-components

<template>
    <div>Child components</div>
</template>
<script>
export default {
    props: {num: {type:String}},// If you want to accept the input from the parent component, you need to write the parameter in setup. The first attribute is this parameter
    setup(props){
        console.log("I am setup");
        console.log(props.num);/ / 22}},</script>
Copy the code

2. Setup parameters

Take the child parent component as an example.

1) Parent component

<template>
    <div>
        <SubComp num="22" text="Hello">
            <p>slot</p>
        </SubComp>
    </div>
</template>
<script>
import SubComp from "Child component path";
export default {
    components:{
        SubComp
    },
}
</script>
Copy the code

2) Sub-components

<template>
    <div>Child components<slot></slot>
    </div>
</template>
<script>
export default {
    props: {
        num: {
            type: String}},// If you want to accept the input from the parent component, you need to write the parameter in setup. The first attribute is this parameter
    /** * The first argument refers to the property passed through * the second argument refers to the context (which can accept the property defined in the word component when the value is passed) * the property included in the context:  context.attrs context.slots context.parent context.root context.emit context.refs */
    /* setup(props, context) {console.log(" I'm setup"); console.log(props.num); // You can also receive console.log(context.attrs.text) with attrs; Console. log(context.slots.default()); }, * /
    setup(props, { attrs, slots, emit }) {
        console.log("I am setup");
        console.log(props.num);
        // Can also be received with attrs
        console.log(attrs.text); / / how are you
        // Retrieve the data passed from the component slot
        console.log(slots.default()); }},</script>
Copy the code

3. See below for the detailed use of setup parameters:

1) props parameters

The props parameter is an object that contains the data passed by the parent component to the child component and all properties received by the child component using the props (the object containing all properties passed by the configuration declaration of the props).

(1) the parent component

<template>
    <h2>The parent component</h2>
    {{msg}}
    <hr />
    <Child :text="msg" />
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import Child from "Component path/file name.vue";
export default defineComponent({
    name: "Home".components: {
        Child
    },
    setup() {
        // Define a data of type REF
        const msg = ref("What am I doing?");

        return{ msg }; }});</script>
Copy the code

(2) the child components

<template>
    <h2>Child components</h2>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
    props: ["text"].setup(props){
        console.log(props);
        console.log(props.text); }})</script>
Copy the code

2) Context parameter

Note: When you use context, you must also use props. This will cause an error.

The context argument is an object: there is an attrs object (an object that gets all the attributes on the current component tag, but that attribute is an object that needs to be passed by the search object that was not declared to accept in the props), an emit method (which distributes the event), and a slots object.

<template>
    <h2>Child components</h2>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
    Setup (props,context){// console.log(); console.log(context.attrs); console.log(context.attrs.text); } * /
    // Use structure assignment shorthand
    setup(props, { attrs, slots, emit }){}})</script>
Copy the code

(1) the parent component

<template>
    <h2>The parent component</h2>
    {{msg}}
    <hr />
    <HelloWorld :text="msg" @fun="fun" />
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import HelloWorld from "@/components/HelloWorld.vue";
export default defineComponent({
    name: "Home".components: {
        HelloWorld,
    },
    setup() {
        // Define a data of type REF
        const msg = ref("What am I doing?");
        const fun = (val:string) = > {
            console.log(val);
            msg.value += val;
        }
        return{ msg, fun }; }});</script>
Copy the code

(2) the child components

<template>
    <h2>Child components</h2>
    <button @click="fun">Update the data</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
    Setup (props,context){} */
    // Use structure assignment shorthand
    setup(props, { attrs, slots, emit }) {
        console.log(attrs);
        console.log(attrs.text);
        // Pass it directly
        emit("fun"."Ha ha ha.");
        // Click and pass
        function fun() {
            emit("fun"."Click on the event.");
        }
        return{ fun }; }})</script>
Copy the code

4, backward transmission value

1) Sub-components

<template>
    <div>Child components</div>
</template>
<script>
export default {
    /* setup(props, context) {emit("myEmit"," I'm sending the value back "); }, * /
    setup(props, { emit }) {
        emit("myEmit"."I'm going backwards."); }},</script>
Copy the code

2) the parent component

<template>
    <div>
        <SubComp @myEmit="myEmit"></SubComp>
    </div>
</template>
<script>
import SubComp from "Child component path";
export default {
    components:{
        SubComp
    },
    setup() {
        function myEmit(val){
            console.log(val);// I am passing values backwards
        }
        // Return whether the method or variable is used in the template
        return { myEmit }
    }
}
</script>
Copy the code

Two, Composition commonly used APIS

Note: All apis are put in setup.

1, ref response

The ref() function is used to create a responsive data object for the given value. The return value of ref() is an object containing only one.value attribute.

Ref is a function:

(1) Function: define a response type data, return is a Ref object, object has a value attribute, if you need to operate on the data, need to use the Ref object call value attribute of the data operation;

② Generally used to define a basic type of responsive data;

③ Operation data in the template:, no. Value;

(4) If we use the ref object/array, we will automatically convert the object/array to reactive proxy object.

<template>
    <div>Commonly used API<hr />
        {{num}}
        <br />
        {{fun()}}
    </div>
</template>
<script>
export default {
    setup() {
        let num = 0;
        let fun = () = > {
            num ++;
            console.log(num);
        }
        return { num, fun }
    }
}
</script>
Copy the code

The calling method is as follows:

<template>
    <div>
        {{num}}
        <input type="text" v-model="num">
        <! If you don't log him off, there is no way to input -->
        <! -- {{fun(2)}} -->
    </div>
</template>
<script>
// Need to be introduced
import { ref } from "vue";
export default {
    setup() {
        let num = ref(0);
        let fun = (val) = > {
            num.value = val;
        }

        return { num, fun }
    }
}
</script>
Copy the code

2. Reactive is used to create a reactive object

When the value created by ref() is directly mounted to reactive(), the reactive data object is automatically expanded to its original value, and it can be accessed directly without using. Value:

Function: define the response of multiple data

Const proxy = reactive(obj): const proxy = reactive(obj): const proxy = reactive(obj): const proxy = reactive(obj): const proxy = reactive(obj)

③ Reactive transformations are “deep” : they affect all nested properties within the object

(4) Internal Proxy based on ES6, the operation of internal data of source objects through Proxy objects is responsive

<template>
    <div>
        <hr />
        {{num}}
        <input type="text" v-model="num">
        <br />
        <! -- {{fun(2)}} -->
        <hr />
        <! -- {{user.name}} -->
        {{name}}
        {{num2}}
    </div>
</template>
<script>
// Need to be introduced
import { reactive, ref, toRefs, readonly, isRef } from "vue";
export default {
    setup() {
        let num = ref(0);
        let fun = (val) = > {
            num.value = val;
        }

        //isRef() determines if it is responsive

        Reactive: reactive; reactive: reactive; reactive: reactive; reactive: reactive
        let user = reactive({
            name: "Uh-huh.".age: 18.num2: num, // Put the ref declaration in this, instead of the value
        })
        function fun2() {
            user.num2 = 100
        }
        fun2();
        // Make responsive data unresponsive by readonly()

        //return {num, fun, user}// (extension operator), except that when expanded, the data is not in the corresponding form
        //return { num, fun, ... User} // This is not a response (...)
        return{ num, fun, ... toRefs(user) }// After introducing the API and using the extension operator, he can respond again}}</script>
Copy the code

When using, the suggestions are as follows:

<! Vue2 component templates must have a pair of tags, but vue3 component templates do not --><template>
    <button @click="updateUser">update</button>
    <br />
    {{user}}
</template>
<script lang="ts">
// defineComponent, which defines a component and can be passed a configuration object internally
import { defineComponent, reactive } from "vue";
export default defineComponent({
    name: "Home".setup() {
        // It is recommended to write multiple objects, so that the following calls are easy
        const user = reactive({
            car: {
                name: "Wang".age: 18,},wife: {
                name: "Xiao Ming".age: 22,}});// function updateUser(){}
        const updateUser = () = > {
            user.car.name = "Ha ha ha.";
            user.wife.age++
            // Delete the implementation in user
            delete user.wife.name
        }
        return{ user, updateUser }; }});</script>
<style scoped>
</style>
Copy the code

Note: It is not possible to update the values of the members of the target object directly by means of the target object, but only by means of the proxy object (reactive data).

3. Computed

Computed () is used to create computed properties and the return value is an instance of ref.

<input type="number" v-model="age"> <br/> Sex: <input type="number" v-model="age"> < input type = "text" v - model = "sex" > < br / > {{name}} - {{age}} - {{sex}} < br / > {{fullName}} < / template > < script > import { reactive, toRefs, computed } from 'vue'; Export default {setup() {const user = reactive({name: "ahhh ", age: 100, sex: reactive) Let fullName = computed(() => {return "name:" + user.name + "-- age:" + user.age}) return {... toRefs(user),fullName } } } </script>Copy the code

4, watch() function

The watch() function is used to monitor changes in certain data items to trigger specific operations. And he has a way to stop it.

1) watch

① The configuration function is the same as that of the Watch

(2) Monitor one or more specified reactive data, and automatically perform the monitoring callback once the data changes

③ By default, no callback is performed during initial initialization. However, you can set immediate to true to specify that the first callback is performed immediately after initial initialization

(4) Set deep to true to specify depth monitoring

2) watchEffect function

(1) Instead of specifying the data to be monitored directly, the responsive data used in the callback function is monitored

(2) By default, the first time will be performed when the initial, so that the data that needs to be monitored can be collected

③ Callback when monitoring data changes

1) ref single variable

<template> listener < button@click ="fun1"> a -- - {{a}} < / button ><button @click="b++">B -- - {{b}}</button>
</template>
<script>
import { ref, watch, watchEffect } from 'vue'
export default {
    setup() {
        let a = ref(1);
        let b = ref(2);

        function fun1() {
            a.value = a.value + 1;
        }
        watch(() = > {
            // Listen to the change of that
            console.log(a.value, b.value);
        })
        watchEffect(() = > {
            console.log(a.value, b.value);
        })
        Array watch([a, b], ([newsA, newsB,], [oldsA, oldsB]) => {
        watch(a, (news, olds) = > {
            console.log("Listen for changes in A.", a.value, "New value", news, "Old value", olds);
        }, { immediate: true }) //immediate:true
        return { a, b, fun1 }
    }
}
</script>
Copy the code

2) Listen for changes to reactive() object

<template> listener < button@click ="a++"> a -- - {{a}} < / button ><button @click="b++">B -- - {{b}}</button>
</template>
<script>
import { reactive, ref, toRefs, watch, watchEffect } from 'vue'
export default {
    setup() {
        const user = reactive({
            a: 1.b: 2
        })
        // Listen for changes in the value of an object (using an array when listening to multiple objects)
        watch(() = > user.a, (news, olds) = > {
            console.log(news, olds);
        })
        WatchEffect (() => {console.log(" I'm watchEffect, it will print once by default ", a); }) watch(user, () => {console.log(" listen to the whole object, it can listen to any changes "); }, {immediate: true}) watch(user, (news, olds) => {console.log(news, olds); }) * /
        return { ...toRefs(user) }
    }
}
</script>
Copy the code

Note: watchEffect immediately executes an incoming function, responds by tracking its dependencies and rerunking the function if its dependencies change.

5. Use of toRefs

When you use return to export an object, then each object is a ref function, but when you export an object, you need to use the point, which is very inconvenient, if you use the extension operator, it will not respond to the data, so you need to use the toRefs function.

Problem: All property values fetched by the reactive object are non-reactive.

Solution: toRefs can be used to convert all the original properties of a reactive object into reactive REFs

ToRefs converts a reactive object into a normal object where each property is a REF

<template>
    <p>{{name}}</p>
    <p>{{age}}</p>
    <button @click="fun">Modify the</button>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
export default defineComponent({
    setup() {
        const obj = reactive({
            name: "Xiao Ming".age: 88});function fun() {
            obj.name = "I change my name to Xiao Wang.";
            console.log(obj);
        }
        // The data will not respond in real time
        // return { ... obj, fun };
        // toRefs converts a reactive object to a normal object, where each property is a ref
        return{... toRefs(obj), fun }; }});</script>
Copy the code

6, ref gets the element

Let the input field automatically get focus:

<template>
    <h2>Ref gets the elements in the page</h2>
    <input type="text" ref="inputRef" />
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from "vue";
export default defineComponent({
    setup() {
        // Requirement: when the page is loaded, the text box in the page can get the focus directly (automatic focus)
        const inputRef = ref<HTMLElement | null> (null);
        onMounted(() = > {
            inputRef.value && inputRef.value.focus();
        });
        return{ inputRef }; }});</script>
Copy the code

7. ShallowReactive and shallowRef

1) shallowReactive: Treats only the outermost properties of an object.

2) shallowRef: Only value responses are processed. Reactive objects are not processed

3) When to use shallow response?

(1) Generally, use ref and reactive

If there is an object whose structure is deep, but its outer properties change, it is shallowReactive

(3) If there is an object data, a new object will be created to replace the ===> shallowRef

4) The depth of the hijack

Reactive (reactive)

<template>
    <p>Reactive: {{m1}}</p>
    <button @click="fun">Change the data</button>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
export default defineComponent({
    setup() {
        const m1 = reactive({
            name: "Xiao Ming".age: 22.car: {
                name: "Bicycle".color: "Red",}});// Add the data
        const fun = () = > {
            // Change reactive's mode
            m1.name += "Uh-huh.";
            m1.car.color = "Blue";
        }
        return{ m1,fun }; }});</script>
Copy the code

(2) shallowReactive

<template>
    <p>ShallowReactive: {{m2}}</p>
    <button @click="fun">Change the data</button>
</template>
<script lang="ts">
import { defineComponent, shallowReactive } from "vue";
export default defineComponent({
    setup() {
        const m2 = shallowReactive({
            name: "Xiao Ming".age: 22.car: {
                name: "Bicycle".color: "Red",}});// Add the data
        const fun = () = > {
            // shallowReactive
            // m2.name += "change ";
            m2.car.color += "Orange";
        }
        return{ m2,fun }; }});</script>
Copy the code

Ref (deep hijack)

<template>
    <p>Ref: {{m3}}</p>
    <button @click="fun">Change the data</button>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
    setup() {
        const m3 = ref({
            name: "Xiao Ming".age: 22.car: {
                name: "Bicycle".color: "Red",}});// Add the data
        const fun = () = > {
            m3.value.car.name += "Change"; 
        }
        return{ m3, fun }; }});</script>
Copy the code

④shallowRef (shallowRef)

<template>
    <p>ShallowRef: {{m4}}</p>
    <button @click="fun">Change the data</button>
</template>
<script lang="ts">
import { defineComponent, shallowRef } from "vue";
export default defineComponent({
    setup() {
        const m4 = shallowRef({
            name: "Xiao Ming".age: 22.car: {
                name: "Bicycle".color: "Red",}});// Add the data
        const fun = () = > {
            m4.value.name += "Change";
            m4.value.car.name += "Change";
            console.log(m4)
        }
        return{ m4 ,fun }; }});</script>
Copy the code

8. Readonly and shallowReadonly

In certain cases where we do not want to update the data, we can wrap a read-only proxy object to read the data, but not modify or delete it.

1) Readonly is a deep read-only

<template>
    <h3>{{state}}</h3>
    <button @click="update">update</button>
</template>

<script lang="ts">
import { reactive, readonly, shallowReadonly } from "vue";
/* readonly: a read-only proxy that gets an object (reactive or pure) or ref and returns the original proxy. The read-only proxy is deep: any nested property accessed is also read-only. * /
export default {
    setup() {
        const state = reactive({
            a: 1.b: {
                c: 2,}});const rState2 = readonly(state);
        // An error is reported during modification
        const update = () = > {
            rState2.b.c++;
        };

        return{ state, update, }; }};</script>
Copy the code

2) shallowReadonly Shallow read-only

<template>
    <h3>{{state}}</h3>
    <button @click="update">update</button>
</template>

<script lang="ts">
import { reactive, readonly, shallowReadonly } from "vue";
/* shallowReadonly: Creates a proxy for shallow read-only data that makes its own property read-only, but does not perform deep read-only conversions for nested objects */
export default {
    setup() {
        const state = reactive({
            a: 1.b: {
                c: 2,}});const rState2 = shallowReadonly(state);
        // An error is reported during modification
        const update = () = > {
            rState2.a++;
            // However, deep data can be modified
            rState2.b.c++;
        };

        return{ state, update, }; }};</script>
Copy the code

9. ToRaw and markRaw

1) toRaw

Returns a generic object converted to a reactive proxy by the reactive or readonly methods.

This is a restore method that can be used for temporary reads, accesses are not proxy-tracked, and interface updates are not triggered when written.

<template>
    <h2>{{state}}</h2>
    <button @click="fun">test</button>
</template>

<script lang="ts">
import { markRaw, reactive, toRaw } from "vue";
export default {
    setup() {
        const state = reactive<any>({
            name: "tom".age: 25});const fun = () = > {
            // Turn the proxy object into a normal object, but the interface is still not updated
            const user = toRaw(state);
            user.age++; // The interface will not be updated
        };
        return{ state, fun }; }};</script>
Copy the code

2) markRaw

Marks an object so that it can never be converted to a proxy. Return the object itself

<template>
    <h2>{{state}}</h2>
    <button @click="fun">test</button>
</template>

<script lang="ts">
import { markRaw, reactive, toRaw } from "vue";
interface Info{
    name:string; age:number; likes ? : string[]; }export default {
    setup() {
        const state = reactive<Info>({
            name: "tom".age: 25});const fun = () = > {
            const likes = ["a"."b"];
            // Objects with markRaw tags are no longer proxy objects
            state.likes = markRaw(likes);// This will not change in the interface
            setInterval(() = > {
                if(state.likes){
                    state.likes[0] + ="--";
                    console.log("Let the timer go."); }},1000)};return{ state, fun, }; }};</script>
Copy the code

Application scenario:

Some values should not be set to reactive, such as complex third-party class instances or Vue component objects.

(2) Skipping the proxy transformation can improve performance when rendering large lists of immutable data sources.

10. Use of toRef

Create a ref object for a property on the source response. both internally operate on the same data value and are synchronized when updated. Difference REF: copy a new data value to operate separately, update does not affect each other.

1) Parent component

<template>
    <h2>State: {{state}}</h2>
    <h2>Age: {{age}}</h2>
    <h2>Money: {{money}}</h2>
    <button @click="fun">Update the data</button>
    <hr >
    <! Select * from component where value is omitted;
    <api-child :age="age" />
</template>
<script lang="ts">
import { defineComponent, reactive, toRef, ref } from "vue";
import apiChild from "./component/apiChild.vue";
export default defineComponent({
    components:{
        apiChild
    },
    setup() {
        const state = reactive({
            age: 5.money: 100});// Change the age attribute in the reactive data state object to the ref object
        const age = toRef(state, "age");
        // Convert one of the properties of the responseobject into a ref object (so they are not bound to each other, and changing the value of state below does not change)
        const money = ref(state.money);
        console.log(age);/ / ref object
        console.log(money);/ / ref object
        // Follow the new data
        function fun() {
            state.age += 2;
            // age.value = 3;
        }
        return{ state, age, money, fun }; }});</script>
Copy the code

2) Sub-components

<template>
    <h3>Child components</h3>
    <p>Age: {{age}}</p>
    <p>Length: {{length}}</p>
</template>
<script lang="ts">
import { defineComponent, computed, Ref, toRef } from "vue";
// The following is a hook function
function useGetLength(age: Ref) {
    return computed(() = > {
        return age.value.toString().length;
    });
}
export default defineComponent({
    props: {
        age: {
            type: Number.required: true.// Must (must pass this)}},setup(props) {
        // Get the passed length in the child component
        const length = useGetLength(toRef(props, "age"));
        return{ length }; }});</script>
Copy the code

11, customRef

Create a custom REF with explicit control over its dependency tracking and update triggering

<template>
    <input type="text" v-model="text" />
    <p>{{ text }}</p>
</template>
<script lang="ts">
import { customRef, defineComponent, ref } from "vue";
// Customize the function of hook stabilization
// value specifies the amount of time the incoming data is of uncertain type, so use the generic type delay. The default is 200 milliseconds
function useDebouncedRef<T> (value: T, delay = 200) {
    // Prepare a variable to store the timer ID
    let time: any;
    // It returns ref(track, trigger in the official document)
    return customRef((track, trigger) = > {
        return {
            // Return data
            get() {
                // Tell Vue to track the data
                track();
                return value;
            },
            // Set the data
            set(newValue: T) {
                // Clean timer
                clearTimeout(time);
                // Start the timer
                time = setTimeout(() = > {
                    value = newValue;
                    // Tell Vue to update the interfacetrigger(); }, delay); }}; }); }export default defineComponent({
    setup() {
        const text = useDebouncedRef("abc".500);
        return{ text, }; }});</script>
Copy the code

12. Judge whether the data is responsive

1) isRef: Checks whether a value is a ref object

2) isReactive: Checks whether an object is a reactive proxy created by reactive

3) isReadonly: Checks whether an object is a read-only agent created by readonly

4) isProxy: Checks whether an object is a proxy created by reactive or readonly methods

Note: The above returns true or false.

Lifecycle hooks

• beforeMount – > onBeforeMount

• mounted – > onMounted

• beforeUpdate – > onBeforeUpdate

• updated – > onUpdated

• beforeUnmount – > onBeforeUnmount

• unmounted – > onUnmounted

Note:

(1) Create component hook function (beforeCreate, created);

② The execution time is the same;

(3) When writing in setup, there is an extra on in front of it, and there is still a callback method inside.

④ Must introduce;

⑤ V-if display hides will trigger the display hides inside the component.

<template> Life cycle </template><script>
// Which life cycle is used, it should be introduced here
import { onMounted } from 'vue'
export default {
    setup(){
        /** * is called at the same time as Mounted, * but when you write in setup, you add on to the front and there is also a callback method * and you must include */ 
        onMounted(() = >{
            console.log("onMounted"); }}})</script>
Copy the code

Use of custom hooks functions

  • Reusable functionality encapsulated using Vue3’s composite API
  • Custom hooks work similar to the mixin technique in VUE2
  • Advantages of custom hooks: it is clear where the code for reuse is coming from, making it easier to understand

1. Case:

1) Collect the page coordinates clicked by the user’s mouse

① On the Vue page

<template>
    <h2>Custom hooks functions</h2>
    <p>X: {{x}}, y: {{y}}</p>
</template>
<script>
import { defineComponent } from 'vue';
/ / 1, introduction
importThe file namefrom "File path/filenames. Ts";
export default defineComponent({
    // Requirement 1: The user clicks on the page, and the horizontal and vertical coordinates of the click position are collected and displayed
    setup() {
        // 2, use the structure assignment
        const{x, y} = file name ();return { x, y }
    },
})
</script>
Copy the code

Create an imported file (this can be ts or JS)

import { onBeforeMount, onMounted, ref } from 'vue';
export default function () {
    const x = ref(-1);
    const y = ref(-1);
    /** * Click callback function *@param Event is a mouse click event, so it has a MouseEvent type */
    function clickHandler(event: MouseEvent) {
        x.value = event.pageX;
        y.value = event.pageY;
    }

    // When the page is loaded, you need the hook
    onMounted(() = > {
        // Write the method here, need to write the callback function above
        window.addEventListener("click", clickHandler);
    })
    // The page closes and the function is unloaded
    onBeforeMount(() = > {
        window.removeEventListener("click", clickHandler);
    })
    // It is used for outside use
    return { x, y }
}
Copy the code

Provide and inject use in the composite API

When you pass data from the parent to the offspring, when the parent passes data to the offspring, you don’t want to pass it through layers.

1. The traditional way

1) Root component or page

<template> Provide and Inject <h1> follow </h1> {{title}} <input type="text" v-model="title">
    <TwoProvide />
</template>
<script>
import TwoProvide from "./component/TwoProvide.vue";
export default {
    components:{
        TwoProvide
    },
    data() {
        return {
            title:"This is related to the data provided by the component or the page."}},// 1, inject (that is, provide data, but the traditional way, can not respond to the data, so the value in the descendant component, will not change)
    provide(){
        return {
            title:this.title
        }
    }
}
</script>
Copy the code

2) Layer 2 components

<template>
    <hr />
    <p>Layer 2 components</p>
    <three-provide />
</template>
<script>
import ThreeProvide from "./ThreeProvide.vue";
export default {
    components:{
        ThreeProvide
    }
}
</script>
Copy the code

3) Layer 3 components

<template>
    <hr />
    <p>Layer 3 components</p>
    {{title}}
</template>
<script>
export default {
    // 2
    inject: ["title"]}</script>
Copy the code

2. Use of setup

1) Root component or page

<template> Provide and Inject <h1> follow </h1> {{title}} <input type="text" v-model="title">
    <TwoProvide />
</template>
<script>
import { ref, provide } from "vue";
import TwoProvide from "./component/TwoProvide.vue";
export default {
    components: {
        TwoProvide
    },
    setup() {
        let title = ref("This is related to the data provided by the component or the page.");
        // 1, inject (that is, provide data, but the traditional way, can not respond to the data, so the value in the descendant component, will not change)
        provide("title", title);

        return{ title }; }}</script>
Copy the code

2) Layer 2 components

<template>
    <hr />
    <p>Layer 2 components</p>
    <three-provide />
</template>
<script>
import ThreeProvide from "./ThreeProvide.vue";
export default {
    components:{
        ThreeProvide
    }
}
</script>
Copy the code

3) Layer 3 components

<template>
    <hr />
    <p>Layer 3 components</p>
    {{title}}
    <input type="text" v-model="title">
</template>
<script>
import { inject } from 'vue'
export default {
    // 2. Use (accept)
    setup() {

        let title = inject("title");
        return { title }
    }
}
</script>
Copy the code

3. The setup object works as follows

Note: Other PI reference address: vue3js.cn/vue-composi…

New components in VuE3

1, Fragment

1) In Vue2: Components must have a root tag

2) In Vue3: Components can have no root tag, and contain multiple tags inside a Fragment virtual element

3) Benefits: Reduced label hierarchy and reduced memory usage

<template> <! </template> </template>Copy the code

2, Teleport(Teleport)

Teleport provides a clean way for a component’s HTML to be inserted under a specific tag (most likely body) outside the parent component’s interface.

Note: You can specify where the component should be displayed.

1) Parent component

<template>
    App
    <DialogBox />
    
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import DialogBox from "Component path/dialogbox.vue";
export default defineComponent({
    components:{
        DialogBox
    }
})
</script>
Copy the code

2) Sub-components

<template>
    <button @click="fun">A dialog box opens</button><! -- This is the dialog box, using the teleport to display the location --><teleport to="body">
        <div v-if="modalOpen" class="modal">
            <div>content<button @click="modalOpen = false">Shut down</button>
            </div>
        </div>
    </teleport>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
    setup() {
        const modalOpen = ref(false);
        function fun() {
            modalOpen.value = true;
        }
        return{ modalOpen, fun }; }});</script>
<style scoped>
.modal {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0.0.0.0.5);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.modal div {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: white;
    width: 300px;
    height: 300px;
    padding: 5px;
}
</style>
Copy the code

Girl 3: Don’t worry about it

Allowing our application to render some backup content while waiting for an asynchronous component allows us to create a smooth user experience.

So if you want to display a component on the page, but the component has to be displayed over a period of time, you can use it on the blank page, you can use it as a skeleton screen.

1) Parent component

<template>
    <h1>The parent component</h1>
    <suspense>
        <! -- V slot:fallback --> v slot:fallback
        <! -- Asynchronous components -->
        <template #default>
            <AsyncComponent />
        </template>
        <! -- What is displayed when the asynchronous component is not loaded -->
        <template v-slot:fallback>
            <h3>Loading...</h3>
        </template>
    </suspense>
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
// Component introduction can be divided into dynamic introduction and static introduction
// 1. Dynamic introduction in VUE2 (can be understood as asynchronous), but not in VUE3
// const AsyncComponent = () => import("./component/AsyncComponent.vue");
// 2. The same stage introduction in VUe3
const AsyncComponent = defineAsyncComponent(
    () = > import("./component/AsyncComponent.vue"));export default defineComponent({
    components: {
        AsyncComponent,
    },
    setup(){}});</script>
Copy the code

2) Sub-components

<template>
    <h2>Asynchronous components</h2>
    {{msg}}
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
    setup() {
        // Simulate an asynchronous operation (usually a data request) here. Async and await can also be used in this section
        return new Promise((resolve, reject) = > {
            setTimeout(() = > {
                resolve({
                    msg: "Hello!!"}); },2000);
        });
    },
    Async setup() {const request = await axios.get(" path "); return { data:request } }, */
});
</script>
Copy the code

7. Combine routing

Params Route transmission parameters

1) Define the rule in the routing file (i.e., determine the key name to be passed)

// The following parameter is not passed. This will resolve the error message (must be written before the parameter).
{ name: "details".path: "details".component: () = > import("Path")},// The id below is the key name
{ name: "details".path: "details/:id".component: () = > import("Path")}Copy the code

2) On the Jump page

<template> Routing API <div> <! -- secondary routing is used --><div id="menu">
            <router-link v-for="item in list" :key="item.id" :to="'/router-api/details/' + item.id">{{item.title}}</router-link>
        </div>
        <div id="content">
            <router-view></router-view>
        </div>
    </div>
</template>
<script>
import { reactive } from 'vue'
export default {
    setup() {
        let list = reactive([
            { title: "List 1".id: 1 },
            { title: "List 2".id: 2 },
            { title: "Listing 3".id: 3 },
            { title: "Listing 4".id: 4}])return { list }
    }
}
</script>
<style scoped>
a{
    display: block;
    margin-top: 20px;
}
#menu {
    width: 30%;
    background: orchid;
    height: 300px;
    float: left;
}
#content {
    width: 70%;
    background: palegreen;
    height: 300px;
    float: right;
}
</style>
Copy the code

3) On the receive page

Details < template > < p > {{$route. Params. Id}} < / p > < p > {{id}} {{detailsId}} < / p > < / template ><script>
import { ref, watch } from 'vue';
import { useRoute, useRouter } from "vue-router";
export default {
    setup() {
        const route = useRoute();
        const router = useRouter();
        let detailsId = ref(route.params.id);
        watch(() = >route.params,(news) = >{
            detailsId.value = news.id;
        })

        return { detailsId }
    },
    computed: {
        // The original method
        id() {
            return this.$route.params.id
        }
    }
}
</script>
Copy the code

2, query pass parameter

1) Jump to the page

<router-link :to="{path: '/ article/router - API, query: {name:' ahhh 'age: 22}}"> jump < / router - the link ><button @click="$router. Push ({path: '/ article/router - API, query: {name:' ha, ha, ha, age: 222}})">jump</button>
Copy the code

2) Receive the page

< the template > article < p > {{$route. The query. The name}} < / p > < / template ><script>
import { ref } from 'vue';
import { useRoute, useRouter } from "vue-router";
export default {
     setup() {
        const route = useRoute();
        const router = useRouter();
        // Use a listener when multiple arguments are used
        console.log(route.query.name); }},</script>
Copy the code

Note: Navigation guards

OnBeforeRouteLeave ((to, from) => {})

onBeforeRouteUpdate(async (to, from) => {})

3. Listen for route changes

<template>
    
</template>
<script>
import { useRouter } from "vue-router";
export default {
    name: 'App'.setup() {
        // Do not need a menu path array
        const noMenu = [ '/login' ];
        const router = useRouter();
        const state = reactive({
            showMenu: true.// Whether to display the menu
        })
        router.beforeEach(to= > {
            console.log(to);
            The // includes() method determines whether an array contains a specified value, returning true if it does, false otherwise.state.showMenu = ! noMenu.includes(to.path); })return { ...toRefs(state) }
    }
}
</script>
Copy the code
/ / global routing front guard (routing is to jump after the page is before the jump from, next is a must to be executed, plus next routing will jump)
router.beforeEach(async (to, from, next) => {
    awaitMethod to execute})Copy the code

4. Switching the routing mode

Hash mode urls always have a # in them

History mode has no #

Router — >index.js

import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router';

const router = createRouter({
    // History: createWebHashHistory(), // Hash mode
    history: createWebHistory(), // History mode (without #)
    routes: [{path: 'path'.name: "index".component: import("Path address")}]})export default router;
Copy the code

8. Combine Vuex

To useStore in setup, you can call the useStore function. This is equivalent to this.$store using the Option API to retrieve within the component.

import { useStore } from ‘vuex’

const store = useStore();

In order to access the status and fetch methods, a computed reference needs to be created to preserve the responsiveness. This is equivalent to using the Option API to create computed properties.

Note: Use method is similar to VUE2.

1. Use of vuex-PersistedState

Note: Solve the problem of data loss after page refresh.