I. Understanding of Vue3

Vue (pronounced vju/curliest, similar to View) is a set of progressive frameworks for building user interfaces. Unlike other large frameworks, Vue is designed to be applied layer by layer from the bottom up. Vue’s core library focuses only on the view layer, making it easy to get started and integrate with third-party libraries or existing projects. On the other hand, when combined with modern toolchains and various supporting libraries, Vue is perfectly capable of providing drivers for complex, single-page applications.

New features: Better performance, smaller package sizes, better TypeScript integration, better API design.

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="app"></div>
    <script>
        const el = {
            template:"< h1 > hello < / h1 >"
        }
        const app = Vue.createApp(el)
        app.mount("#app");
    </script>
</body>
</html>
Copy the code

Note: Vue can be used in two ways in HTML

① Use the script tag of type X-template

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="app"></div>
    <script type="x-template" id="box">
        <div>
            {{num}}
        </div>
    </script>
    <script>
        Vue.createApp({
            template: "#box".data() {
                return {
                    num: 999
                }
            },
        }).mount("#app")
    </script>
</body>
</html>
Copy the code

The template tag is often used because it will not be rendered because it is an HTML tag. See developer.mozilla.org/zh-CN/docs/…

The template element is a mechanism for holding client-side content that is not rendered when the page loads, but can then be instantiated at run time using JavaScript.

Think of a template as a piece of content that can be stored in a document for later use. While the parser does process the content of ** * elements when loading the page, it does so only to ensure that the content is valid; But the element content is not rendered.

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
        <title>Document</title>
        <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
        <div id="app"></div>
        <template id="box">
            {{ num }}
        </template>
        <script>
            Vue.createApp({
                template: "#box".data() {
                    return {
                        num: 99
                    }
                },
            }).mount("#app")
        </script>
    </body>
</html>
Copy the code

1. Download vue source code

① You are advised to use Github clone.

git clone [email protected]:vuejs/vue-next.git
Copy the code

② If you are downloading the compressed package, you need to do the following:

Note: the meaning of the following instructions, baidu.

A, yarn install

B, git init

C, git add.

D, git ommit -m

2, run,

Modify the package.json file before running it. Add –sourcemap to the end of the command so that you can see the source code when debugging vue.global.js.

yarn dev
Copy the code

After running it, it will package the files in the package and generate a vue file — >dist — >vue.global.js (this is the file that needs to be used and vue.global.js.map is the mapping file).

3, debugging,

Create a demo folder under examples (examples) and write examples in the demo folder, such as demo.html.

<! Open HTML In Default Browser -->
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
    <script src=".. /.. /dist/vue.global.js"></script>
    <script>
        debugger;
        Vue.createApp({
            template:"< h1 > hello! "
        }).mount("#app")
    </script>
</body>
</html>
Copy the code

② Source location view

Note: Function of key:

Key special attributes are mainly used as hints for Vue’s virtual DOM algorithm to identify VNodes when comparing old and new node groups. If keys are not used, Vue uses an algorithm to minimize element movement and tries to modify/reuse elements of the same type in place whenever possible. With keys, it rearranges the elements based on the order of the key, and elements where the key no longer exists are always removed/destroyed.

Use of V-bind

Note: ① The following keys can be used without quotation marks

② Value is a variable without quotation marks

③ You can also call an object below, but it is more recommended to use computed properties

1. Bind class

<template>
    <div>
        <! -- 1, common grammar -->
        <div :class="one"></div>
        <! {' class name ': Boolean, 'class name ': Boolean}
        <div :class="{'className2': true}"></div>
        <! You can place the object in a single property.
        <div :class="obj1"></div>
        <! Pass array -->
        <! -- 4 -- 1, array elements -->
        <div :class="['className4-1', two]">Four 1</div>
        <! An array can also be a ternary operator or a bound variable.
        <div :class="['className4-2', bool ? 'className4-2-a':'']">Four 2</div>
        <! 4, array can also be object syntax -->
        <div :class="[obj1, {'className4-3': bool}]">Four 3</div>
    </div>
</template>

<script>
import { reactive, ref } from 'vue'
export default {
    name: 'XXXXX'.setup() {
        const one = ref("className1")
        const obj1 = reactive({ className3: true })
        const two = ref("className4-1-a")
        const bool = ref(true)
        return { one, obj1, two, bool }
    }
}
</script>

<style scoped>
.className1 {
    color: red;
}
.className2 {
    color: royalblue;
}
.className3 {
    color: pink;
}
.className4-1 {
    color: seagreen;
}
.className4-1-a {
    font-size: 20px;
}
.className4-2 {
    color: red;
}
.className4-2-a {
    font-size: 22px;
}
.className4-3 {
    font-size: 30px;
}
</style>
Copy the code

2. Bind style

Font size: Use a hump (fontSize) or a string (‘font size’)

<template>
    <div :style="{height: '200px', width: '200px', 'background-color': 'red'}"></div>
    <div :style="obj1"></div><! -- Array contains multiple objects, which can be merged with each other --><div :style="[{fontSize: size + 'px',color:'red'}, obj1]">Ha ha ha ha</div>
</template>

<script>
import { reactive, ref } from '@vue/reactivity'
export default {
    name: 'XXXXX'.setup() {
        const obj1 = reactive({ height: '200px'.width: '200px'.backgroundColor: 'pink' })
        let size = ref(40)
        return { obj1, size }
    }
}
</script>
Copy the code

3. Dynamically bind properties

<template>
    <div :[key] ="value"></div>
</template>

<script>
import { reactive, ref } from '@vue/reactivity'
export default {
    name: 'XXXXX'.setup() {
        const key = ref("class");
        const value = ref("box");
        return { key, value }
    }
}
</script>

<style scoped>
.box {
    width: 100px;
    height: 100px;
    background-color: pink;
}
</style>
Copy the code

4. Bind an object

<template>
    <div v-bind="obj">
        <! <div dir="dir" lang="zh"></div> -->
    </div>
</template>

<script>
import { reactive, ref } from '@vue/reactivity'
export default {
    name: 'XXXXX'.setup() {
        const obj = reactive({
            dir: "dir".// Specify the order in which the contents of the elements are read
            lang: "zh" // Sets the language to be used in the element
        })
        return { obj }
    }
}
</script>

<style scoped>
div {
    width: 100px;
    height: 100px;
    background-color: pink;
}
</style>
Copy the code

Iii. Use of Watch

With the deep option, the old value will be the same as the new value because their references point to the same object/array. Vue does not keep a copy of the value before the change.

1. Basic use

<template>
    <div>
        <p>Watch the listener</p>
        <button @click="fun">Click on the</button>
        {{ info }}
    </div>
</template>

<script>
export default {
    name: 'Watch'.data() {
        return {
            info: { name: "Xiao Ming".age: 22}}},watch: {
        info(newValue, oldValue) {
            console.log("New value" , newValue, "Old value", oldValue); }},methods: {
        fun() {
            this.info = { name: "Flower"}; }}}</script>
Copy the code

2. Configuration of Watch

<template>
    <div>
        <p>Watch the listener</p>
        <button @click="fun">Click on the</button>
        {{ info }}
    </div>
</template>
<script>
export default {
    name: 'Watch'.data() {
        return {
            info: { name: "Xiao Ming".age: 22}}},watch: {
        // Just change a property in the object. Watch does not fire but the view changes
        info(newValue, oldValue) {
            console.log("New value" , newValue, "Old value", oldValue); }},methods: {
        fun() {
            // Change only one property in the object
            this.info.name = "Flower"; }}}</script>
Copy the code

So depth monitors are used for this kind of use

<template>
    <div>
        <p>Watch the listener</p>
        <button @click="fun">Click on the</button>
        {{ info }}
    </div>
</template>

<script>

export default {
    name: 'Watch'.data() {
        return {
            info: { name: "Xiao Ming".age: 22}}},watch: {
        // Deep listening, immediate execution
        info: {
            handler: function (newValue, oldValue) {
                console.log("New value", newValue, "Old value", oldValue);
            },
            deep: true , // Deep is true
            immediate: true // When a new page is loaded, the listener is not executed. If the page needs to be rendered, it must be executed immediately}},methods: {
        fun() {
            this.info.name = "Flower"; }}}</script>
Copy the code

3. Trigger methods when listening elements change

<template>
    <div>
        <p>Watch the listener</p>
        <button @click="fun">Click on the</button>
        {{ info }}
    </div>
</template>

<script>

export default {
    name: 'Watch'.data() {
        return {
            info: 0}},watch: {
        info: "change",},methods: {
        fun() {
            this.info++;
        },
        change(newValue, oldValue) {
            console.log("New value", newValue, "Old value", oldValue); }}}</script>
Copy the code

4. Listen for element changes and trigger multiple methods

Note: This will be called one by one.

<template>
    <div>
        <p>Watch the listener</p>
        <button @click="fun">Click on the</button>
        {{ info }}
    </div>
</template>

<script>
export default {
    name: 'Watch'.data() {
        return {
            info: 0}},watch: {
        // Deep listening, immediate execution
        info: [
            "change",
            {
                handler: function (newValue, oldValue) {
                    console.log("New value", newValue, "Old value", oldValue);
                },
                deep: true.// Deep is true
                immediate: true   // When a new page is loaded, the listener is not executed. If the page needs to be rendered, it must be executed immediately}},methods: {
        fun() {
            this.info ++;
        },
        change(newValue, oldValue) {
            console.log("New value", newValue, "Old value", oldValue); }}}</script>
Copy the code

5. During page initialization, tell Watch who you want to listen on

Note: this.$watch() passes three arguments (the third as needed), the first to listen on, the second to call back to the function, and the third to configure options (which are passed as objects). It also has a return value that you can unlisten on when you call it.

<template>
    <div>
        <p>Watch the listener</p>
        <button @click="fun">Click on the</button>
        <button @click="cancleWatch">Cancel to monitor</button>
        {{ info }}
    </div>
</template>
<script>
export default {
    name: 'Watch'.data() {
        return {
            info: { name: "Xiao Ming".age: 22 },
            cancel: null}},methods: {
        fun() {
            this.info.age++;
        },
        cancleWatch() {
            // Cancel the listener
            this.cancel(); }},created() {
        The first argument is the listening object, the second callback function, the third argument is the configuration option (the configuration option is passed as an object), and it also has a return value. When you call this return value, you can cancel the listening
        this.cancel = this.$watch("info".(newValue, oldValue) = > { // You can write the arrow function here, or you can not write the arrow
            console.log("New value", newValue, "Old value", oldValue);
        }, {
            deep: true.immediate: true}}})</script>
Copy the code

4. Component communication

1. Parent component passes value to child component

Website reference: v3.cn.vuejs.org/guide/compo…

1) Child components receive values as arrays

Note: This method does not define the type, default value, etc. It is generally not used.

(1) the parent component

<template>
    <div>
        <son-one title="Ha ha ha." content="Hello! I'm hahaha."></son-one>
        <son-one :title="title" :content="content"></son-one>
        <! -- Easy way -->
        <son-one v-bind="obj"></son-one>

    </div>
</template>
<script>
import SonOne from "./SonOne.vue"
export default {
    components: {
        SonOne
    },
    data() {
        return {
            title: "Ha ha".content: "Hello! I'm hehe."./** * If you are an object, you can use this simple method */
            obj: {
                title: "Lala".content: "Hello! I'm a lesbian."}}}},</script>
Copy the code

(2) the child components

<template>
    <div>
        <p>{{title}}</p>
        <p>{{content}}</p>
    </div>
</template>
<script>

export default {
    props: ["title"."content"].components: {},data() {
        return{}}},</script>
Copy the code

2) The usage of objects

(1) the parent component

<template>
    <div>
        <son-one title="Ha ha ha." content="Hello! I'm hahaha."></son-one>
        <son-one :title="title" ></son-one>
        <! -- Easy way -->
        <son-one v-bind="obj"></son-one>
    </div>
</template>
<script>
import SonOne from "./SonOne.vue"
export default {
    components: {
        SonOne
    },
    data() {
        return {
            title: "Ha ha".content: "Hello! I'm hehe."./** * If you are an object, you can use this simple method */
            obj: {
                title: "Lala".content: "Hello! I'm a lesbian."}}}},</script>
Copy the code

(2) the child components

<template>
    <div>
        <p>{{title}}</p>
        <p>{{content}}</p>
    </div>
</template>
<script>

export default {
    props: {
        title: String./** ** specifies more stuff */
        content: {
            /* Specifies the type */
            type:String./** * Mandatory properties * Default: false */
            required: true./* Define a default value when not worn, of course, the mandatory attribute or the default value */
            default:"Default value"}}}</script>
Copy the code

3) What are the types

String

Number

Boolean

Array

Object

Date

Function

Symbo

(1) the parent component

<template>
    <div>
        <! In HTML, the uppercase is not case-sensitive. In HTML, the uppercase is converted to lowercase. But the vue loader does this for you, so when you pass the value, you can write it in uppercase.
        <son-one str="Ha ha ha." :num="1" multiple-types="Hello! custom-verification="Ha ha" :fun="fun"></son-one>
    </div>
</template>
<script>
import SonOne from "./SonOne.vue"
export default {
    components: {
        SonOne
    },
    data() {
        return {
            title: "Ha ha".content: "Hello! I'm hehe."./** * If you are an object, you can use this simple method */
            obj: {
                title: "Lala".content: "Hello! I'm a lesbian."}}},methods: {
        fun(){
            console.log("Function passed in"); }}},</script>
Copy the code

(2) the child components

<template>
    <div>
        <p>{{ str }}</p>
        <p>{{ num }}</p>
        <p>{{ multipleTypes }}</p>
        <p>{{obj}} : {{obj. STR}}</p>
        <p>{{ customVerification }}</p>
    </div>
</template>
<script>

export default {
    props: {
        /* String */
        str: String./* Numbers with default values */
        num: {
            /* Specifies the type */
            type: Number./* Define a default value when not worn, of course, the mandatory attribute or the default value */
            default: 1
        },
        /* Multiple type judgment, that is, can pass multiple types */
        multipleTypes: [Number.String]./** * objects with default values (reference types) * this time you have to return, which causes pointing problems. The value of one component changes, and the value of other reference components also changes */
        obj: {
            type: Object.// Each object is an independent object
            default() {
                return { str: "Ha ha ha.".num: 1}}},/** * A custom validation function can verify that the value you pass in is valid. */ means that the value you pass in can only be one of these three strings
        customVerification: {
            validator(val) {
                return ["Hello"."Ha ha"."Ha ha"].includes(val); }},/** * functions with default values */
        fun: {
            type: Function.default() {
                return "Default function"}}},created() {
        this.fun();
    },
    data() {
        return{}}},</script>
Copy the code

2. Non-prop attributes

V3.cn.vuejs.org/guide/compo…

Note: This means passing a property to the component, such as style, ID, class.

1) If I have a root node (single root node)

Note: A child component has a root element

Add styles to the tag directly when used.

You can also disable child components from inheriting styles from parent components by writing:

② You can also specify the location inheritance style as follows:

③ Pass in multiple attributes at once:

A. Parent component

<template>
    <div>
        <! In HTML, the uppercase is not case-sensitive. In HTML, the uppercase is converted to lowercase. But the vue loader does this for you, so when you pass the value, you can write it in uppercase.
        <son-one str="Ha ha ha." :num="1" multiple-types="Hello! custom-verification="Ha ha" :fun="fun" class="box" id="only"></son-one>
    </div>
</template>
<script>
import SonOne from "./SonOne.vue"
export default {
    components: {
        SonOne
    },
    data() {
        return {
            title: "Ha ha".content: "Hello! I'm hehe."./** * If you are an object, you can use this simple method */
            obj: {
                title: "Lala".content: "Hello! I'm a lesbian."}}},methods: {
        fun(){
            console.log("Function passed in"); }}},</script>
Copy the code

B. Sub-components

<template>
    <div>
        <p v-bind="$attrs">{{ str }}</p>
        <p>{{ num }}</p>
        <p>{{ multipleTypes }}</p>
        <p>{{obj}} : {{obj. STR}}</p>
        <p>{{ customVerification }}</p>
    </div>
</template>
<script>

export default {
    // Close inherited
    inheritAttrs: false.props: {
        /* String */
        str: String./* Numbers with default values */
        num: {
            /* Specifies the type */
            type: Number./* Define a default value when not worn, of course, the mandatory attribute or the default value */
            default: 1
        },
        /* Multiple type judgment, that is, can pass multiple types */
        multipleTypes: [Number.String]./** * objects with default values (reference types) * this time you have to return, which causes pointing problems. The value of one component changes, and the value of other reference components also changes */
        obj: {
            type: Object.// Each object is an independent object
            default() {
                return { str: "Ha ha ha.".num: 1}}},/** * A custom validation function can verify that the value you pass in is valid. */ means that the value you pass in can only be one of these three strings
        customVerification: {
            validator(val) {
                return ["Hello"."Ha ha"."Ha ha"].includes(val); }},/** * functions with default values */
        fun: {
            type: Function.default() {
                return "Default function"}}},created() {
        this.fun();
    },
    data() {
        return{}}},</script>
<style scoped>
.box{
    color: red;
}
#only{
    font-size: 30px;
}
</style>
Copy the code

2) Multiple root nodes

Note: When a child element has multiple root nodes and the parent element passes a class, if you do not specify it, it will report the following error:

3. Child components pass values to parent components

When passing a value, you need to define the name of the value to be passed by the child component to the parent component first, which can be written in two ways: array and object.

1) Array writing

(1) child components

<template>
    <div>
        <button @click="add">+ 1</button>
        <button @click="reduce">- 1</button>
        <br />Custom add several:<input type="text" v-model.number="num">
        <button @click="customize">+{{num}}</button>
    </div>
</template>
<script>

export default {
    name: 'CounterOperation'.components: {},/** * 1; /** * 2; /** * 2; 2. You can also write objects */
    emits: ["add"."sub"."customize"].data() {
        return {
            num: 0}},methods: {
        add(){
            // console.log("+1");
            /** * 2
            this.$emit("add");
        },
        reduce(){
            // console.log("-1");
            this.$emit("sub");
        },
        customize(){
            /** * can pass multiple arguments */
            this.$emit("customize".this.num); }}},</script>
Copy the code

(2) the parent component

<template>
    <div>Calculator: {{counter}}<counter-operation @add="addOne" @sub="subOne" @customize="customize" />
    </div>
</template>
<script>
import CounterOperation from "./CounterOperation.vue";
export default {
    name: 'index'.components: {
        CounterOperation
    },
    data() {
        return {
            counter:0}},methods: {
        addOne(){
            this.counter++
        },
        subOne(){
            this.counter--
        },
        customize(num){
            // console.log(num);
            this.counter += num; }}},</script>
Copy the code

2) Object writing, object writing, can verify the pass value

(1) child components

<template>
    <div>
        <button @click="add">+ 1</button>
        <button @click="reduce">- 1</button>
        <br />Custom add several:<input type="text" v-model.number="num">
        <button @click="customize">+{{num}}</button>
    </div>
</template>
<script>

export default {
    name: 'CounterOperation'.components: {},/** * 1; /** * 2; /** * 2; 2. You can also write objects */
    // Object notation can validate arguments
    emits: {
        // null indicates that validation of the parameter type is not required
        add: null.sub: null.Return true * Note: if the parameter fails, it will still pass through. If the parameter does not match, it will only send a warning 
        customize: payload= > {
            console.log(payload);
            return true}},data() {
        return {
            num: 0}},methods: {
        add(){
            // console.log("+1");
            /** * 2
            this.$emit("add");
        },
        reduce(){
            // console.log("-1");
            this.$emit("sub");
        },
        customize(){
            /** * can pass multiple arguments */
            this.$emit("customize".this.num); }}},</script>
Copy the code

(2) the parent component

<template>
    <div>Calculator: {{counter}}<counter-operation @add="addOne" @sub="subOne" @customize="customize" />
    </div>
</template>
<script>
import CounterOperation from "./CounterOperation.vue";
export default {
    name: 'index'.components: {
        CounterOperation
    },
    data() {
        return {
            counter:0}},methods: {
        addOne(){
            this.counter++
        },
        subOne(){
            this.counter--
        },
        customize(num){
            this.counter += num; }}},</script>
Copy the code

4. Tabs switch case

1) Parent component

<template>
    <div>
        <tabs :title="title" :contents="contents" @throw="throw" />
        <h1>{{contents[currentIndex]}}</h1>
    </div>
</template>
<script>
import tabs from "./tabs.vue"
export default {
    name: 'index'.components:{
        tabs
    },
    data() {
        return{
            title: ["Clothes"."Shoes"."Package"].contents: ["Clothes page"."Shoes page"."Package page"].currentIndex: 0}},methods: {
        throw(index){
            this.currentIndex = index; }}},</script>
Copy the code

2) Sub-components

<template>
    <div>
        <div v-for="(item,index) in title" :key="index" class="item" :class="{active: currentIndex === index}" @click="fun(index)">
            <span>{{item}}</span>
        </div>
    </div>
</template>
<script>

export default {
    name: 'tabs'.props: {
        title: Array
    },
    components: {},data() {
        return {
            currentIndex: 0}},methods: {
        fun(index){
            this.currentIndex = index;
            this.$emit("throw".this.currentIndex)
        }
    },
}
</script>

<style scoped>
div {
    display: flex;
}
.item {
    flex: 1;
    text-align: center;
}
.item > span {
    width: 100%;
}
.active {
    color: red;
}
.active > span {
    padding: 0 0px 5px;
    border-bottom: 3px solid red;
}
</style>
Copy the code

5. Communication of non-parent and child components

Provide and Inject data of grandchild component.

1) use

Grandpa component

<template>
    <div>Grandpa components<hr />
        <father />
    </div>
</template>
<script>
import father from "./father.vue";
import { computed } from "vue"
export default {
    name: 'grandfather'.components: {
        father
    },
    data() {
        return {
            num: 9}},/** * Define data * but only for descendant component use, current component can not use * note: 2. When assigning, it will not change the value of the assignment, so it will use the calculated property, but the use of the method may be different from the previous */
    /* provide: {obj: {name: "riess ", age: 26}} */
    provide() {
        return {
            /** * but this will return an object, so use.value */
            num: computed(() = > {
                return this.num
            }),
            obj: {
                name: "里斯".age: 26}}}}</script>
Copy the code

(2) the parent component

<template>
    <div>His component<hr />
        <son />
    </div>
</template>
<script>
import son from "./son.vue"
export default {
    name: 'grandfather'.components:{
        son
    },
}
</script>
Copy the code

(3) child components

<template>
    <div>The grandson components<p>{{obj.name}}</p>
        <p>{{obj.age}}</p>
        <p>{{num.value}}</p>
    </div>
</template>
<script>

export default {
    name: 'grandfather'./** * use data */
    inject: ["obj"."num"],}</script>
Copy the code

Use of the global event bus

Note: Vue3 removes the ON, ON, ON, off, and $once methods from the instance, so if we want to continue using the global event bus, we go through a third-party library.

1) Mitt download:

npm install mitt
Copy the code

2) When using third-party libraries, try to package them as a component

3) Implement a communication across parent and child components

① Encapsulate a bridge

/** * put this in utils */

// 1
import mitt from "mitt";
/ 2, use the * * * * that I can write more * /
const emitter = mitt();
export default emitter;
Copy the code

5. Slot usage

1. The default content of the slot

① Reference component

<template>
    <div>
        <p>The use of the solt</p>
        <translate>Ha, ha, ha</translate>
        <translate />
    </div>
</template>
<script>
import Translate from "./Translate.vue";
export default {
    name: 'index'.components:{
        Translate
    }
}
</script>
Copy the code

② Components of SolT

<template>
    <div>
        <! -- default content is used when no value is passed -->
        <slot>Default content</slot>
    </div>
</template>
<script>

export default {
    name: 'Translate',}</script>
Copy the code

2, named slot

Note: Slots have a default name: name = “default”.

<! -- Default name of slot --><solt name="default"></solt>
Copy the code

① Named slot

<template>
    <div class="box">
        <! -- default content is used when no value is passed -->
        <div class="left">
            <slot name="left">Default content</slot>
        </div>
        <div class="right">
            <slot name="right">Default content</slot>
        </div>

    </div>
</template>
<script>

export default {
    name: 'Translate',}</script>
<style scoped>
.box {
    display: flex;
    width: 100%;
}
.left..right {
    width: 50%;
    height: 200px;
}
.left{
    background-color: red;
}
.right{
    background-color: royalblue;
}
</style>
Copy the code

② Use named slots

<template>
    <div>
        <p>The use of the solt</p>
        <translate>
            <template v-slot:left>On the left side of the</template>
            <template v-slot:right>The right of the</template>
        </translate>
    </div>
</template>
<script>
import Translate from "./Translate.vue";
export default {
    name: 'index'.components:{
        Translate
    }
}
</script>
Copy the code

3. Dynamic slot name

Note: Encapsulation of advanced components, slot name (name) is not written dead.

(1) using

<template>
    <div>
        <p>The use of the solt</p>
        
        <translate :name="name">
            <template v-slot:right>Named slot</template>
            <! -->
            <template v-slot:[name] >Dynamic slot, passing in different class names</template>
        </translate>
    </div>
</template>
<script>
import Translate from "./Translate.vue";
export default {
    name: 'index'.components: {
        Translate
    },
    data() {
        return {
            name: "left"}}},</script>
Copy the code

② Slot components

<template>
    <div class="box">
        <p>
            <slot name="right"></slot>
        </p>
        <! -- Dynamic slot -->
        <p>
            <slot :name="name"></slot>
        </p>
    </div>
</template>
<script>

export default {
    name: 'Translate'.props: {
        name: {
            type: String.default() {
                /** * Slot default name */
                return "default"}}}}</script>
Copy the code

4. Short for slot

5. Scope slot

Note: This means using the child’s variables in the parent component.

1) Do not specify slot name:

(1) the parent component

<template>
    <div>
        <p>The use of the solt</p>
        
        <translate :tabs="tab">
            <! Select * from parent;
            <template v-slot="slotScope">
                <div>{{slotscope.item}} -- {{slotscope.index}}</div>                
            </template>
        </translate>
    </div>
</template>
<script>
import Translate from "./Translate.vue";
export default {
    name: 'index'.components: {
        Translate
    },
    data() {
        return {
            tab:[
                {name:"Tag 1"},
                {name:"Tag 2"},
                {name:"Tag 3"},
                {name:"Tag 4"}}},}</script>
Copy the code

(2) the child components

<template>
    <div class="box">
        <template v-for="(item,index) in tabs" :key="index">
            <! Insert attributes into slots, then use -->
            <slot :item="item" :index="index"></slot>
        </template>
    </div>
</template>
<script>

export default {
    name: 'Translate'.props: {
        tabs: {
            type: Array.default() {
                return[]}}}}</script>
Copy the code

2) Specify the slot name

(1) the parent component

<template>
    <div>
        <p>The use of the solt</p>
        
        <translate :tabs="tab">
            <! Select * from parent;
            <template v-slot:one="slotScope">
                <div>{{slotscope.item}} -- {{slotscope.index}}</div>                
            </template>
        </translate>
    </div>
</template>
<script>
import Translate from "./Translate.vue";
export default {
    name: 'index'.components: {
        Translate
    },
    data() {
        return {
            tab:[
                {name:"Tag 1"},
                {name:"Tag 2"},
                {name:"Tag 3"},
                {name:"Tag 4"}}},}</script>
Copy the code

(2) the child components

<template>
    <div class="box">
        <template v-for="(item,index) in tabs" :key="index">
            <! Insert attributes into slots, then use -->
            <slot name="one" :item="item" :index="index"></slot>
        </template>
    </div>
</template>
<script>

export default {
    name: 'Translate'.props: {
        tabs: {
            type: Array.default() {
                return[]}}}}</script>
Copy the code

Dynamic components

1. Basic use

Example of implementing a TAB:

2. Pass values and pass events

(1) the parent component

<template>
    <div>
        <p>Use of dynamic components</p>
        <button v-for="item in tabs" :key="item.lable" @click="fun(item)" :class="{ active: com === item.lable }">
            {{ item.value }}
        </button>
        <component :is="com" :num="99" @throw="throw"></component>
    </div>
</template>
<script>
import TabTwo from "./TabTwo.vue"
import TabOne from "./TabOne.vue"
export default {
    name: 'index'.components: {
        TabOne,
        TabTwo
    },
    data() {
        return {
            tabs: [{ value: "Component 1".lable: "TabOne" }, { value: "Component 1".lable: "TabTwo"}].com: "TabOne"}},methods: {
        fun(obj) {
            this.com = obj.lable
        },
        throw(val) {
            console.log(val); }}}</script>

<style scoped>
.active {
    border: 1px solid rebeccapurple;
}
button {
    background-color: transparent;
    border: 0;
    margin: 0 10px;
}
</style>
Copy the code

Component 1 (Value transmission component)

<template>
    <div>
        <p>Dynamic Component 1</p>
        {{num}}
    </div>
</template>
<script>

export default {
    name: 'index'.props: {
        num: {
            type: Number.default() {
                return 0}}}}</script>
Copy the code

③ Component 2 (child throws event to husband)

<template>
    <div>
        <p>Dynamic Component 2</p>
        <button @click="throwAnEvent">Throwing events</button>
    </div>
</template>
<script>

export default {
    name: 'index'./** * Throws an event */
    emits: ["throw"].methods: {
        throwAnEvent() {
            this.$emit("throw".99)}}}</script>
Copy the code

Vii. Webpack subcontracting

1. Default packaging process

1) By default, when building the entire tree of components, webPack packs component modules together at package time (e.g. in an app.js file) because components are directly dependent on each other through modularity;

2) At this time, as the project continues to grow, the content of app.js file is too large, which will slow down the rendering speed of the first screen.

2, packaging, code subcontracting

1) For some components that do not need immediate use, we can separate them into small code blocks chunk.js;

2) For some components that do not need immediate use, we can separate them into small chunks of chunk.js.

3. Subcontracting of WENpack in VUE

Note:

Modules imported through the import function will be subcontracted by Webpack when they are packaged. After subcontracted, they will not be entered into app.js.

/** ** Use of subcontracting */ import("@/utils/subcontract").then(res => {
    console.log(res.operation(10, 10));

})
Copy the code

Vue defineAsyncComponent

DefineAsyncComponent is used when we need to load components asynchronously in a project.

Documents: v3.cn.vuejs.org/api/global-…

DefineAsyncComponent takes two arguments:

1) The factory function that needs to return a Promise object

<template>
    <div>
        <Home />
        <About />
    </div>
</template>
<script>
import { defineAsyncComponent } from "vue";
import Home from "./views/Home.vue";
const About = defineAsyncComponent(() = > import("./views/About.vue"))
export default {
    components:{
        Home,
        About
    }
}
</script>
Copy the code

2) Take an object type and configure the asynchronous function

<template>
    <div>
        <Home />
        <About />
    </div>
</template>
<script>
import { defineAsyncComponent } from "vue";
import Home from "./views/Home.vue";
import Loading from "@/components/Loading.vue";
// const About = defineAsyncComponent(() => import("./views/About.vue"))
const About = defineAsyncComponent({
    loader: () = > import("./views/About.vue"),
    /** * It is an asynchronous component: LoadingComponent configudes a booth component, i.e. Loading * errorComponent When the component fails to load, The component you are showing is the delay in front of the actual loadingComponent. OnError is a listening error, that is, an asynchronous component fails to load
    loadingComponent: Loading,
    delay: 200./** * onError Parameter Meaning * Err error information * Retry function, which calls retry attempts to reload * fail a function indicating that the loader ends and exits * Attempts record the number of attempts */
    onError: function(err, retry, fail, attempts){
        console.log(err, retry, attempts); }})export default {
    components:{
        Home,
        About
    }
}
</script>
Copy the code

Suspense 2. Asynchronous components and Suspense

Suspense 1) Suspense is a built-in global component that has two slots:

(1) Default: If default can be displayed, display the content of default.

② Fallback: If default cannot be displayed, the contents of the fallback slot will be displayed.

2) The usage mode is as follows:

Ix. Use of ref

1. Get elements

1) DOM manipulation is not recommended in Vue development;

2) Bind a ref attribute to an element or component.

The component instance has a $refs attribute

It is an Object that holds all DOM elements and component instances registered with ref Attributes.

Note: By defining a ref on a component, you can get methods, variables, DOM, and so on inside the component.

(1) the parent component

<template>
    <div>
        <p ref="try">The parent component</p>
        <zu-jian ref="zujian" />
    </div>
</template>
<script>
import ZuJian from './ZuJian.vue';

export default {
    components: { ZuJian },
    name: 'index'.mounted() {
        console.log(this.$refs.try);
        console.log(this.$refs.zujian);
        console.log(this.$refs.zujian.num);
        console.log(this.$refs.zujian.fun(1)); }},</script>
Copy the code

(2) the child components

<template>
    <div>component</div>
</template>
<script>

export default {
    name: 'ZuJian'.components:{
        
    },
    data() {
        return{
            num: 10}},methods: {
        fun(val){
            console.log(val);
            return val
        }
    },
}
</script>
Copy the code

Ten,
p a r e n t and The parent and
root

Access the parent element with $parent

(1) child components

<template>
    <div>component<button @click="fun1">Get the parent component</button>
    </div>
</template>
<script>

export default {
    name: 'ZuJian'.components:{
        
    },
    data() {
        return{
            num: 10}},methods: {
        fun(val){
            console.log(val);
            return val
        },
        fun1(){
            console.log(this.$parent.obj); }}},</script>
Copy the code

(2) the parent component

<template>
    <div>
        <p ref="try">The parent component</p>
        <zu-jian ref="zujian" />
    </div>
</template>
<script>
import ZuJian from './ZuJian.vue';

export default {
    components: { ZuJian },
    name: 'index'.data() {
        return {
            obj: {
                name: "Xiao Ming"}}},mounted() {
        console.log(this.$refs.try);
        console.log(this.$refs.zujian);
        console.log(this.$refs.zujian.num);
        console.log(this.$refs.zujian.fun(1)); }},</script>
Copy the code

$root = app.vue

The life cycle of vUE

Component V-Model

1. Use of API

(1) the parent component

<template>
    <div>
        <p>Use v-Models on elements</p>
        <input type="text" v-model="text"><br />
        <! Principle of -- -- -- >
        <input type="text" :value="text" @input="text = $event.target.value">
        <hr />
        <p>Use v-Models on components</p>
        {{textComponent}}
        <test-input v-model="textComponent" />
        <! Principle of -- -- -- >
        <! -- <test-input :modelValue="textComponent" @updata:model-value="textComponent = $event" /> -->
    </div>
</template>
<script>
import TestInput from './TestInput.vue'

export default {
    name: 'index'.components: {
        TestInput

    },
    data() {
        return {
            text: "".textComponent: "Hello!}}},</script>
Copy the code

(2) the child components

<template>
    <div>
        <button @click="fun">button</button>
        {{modelValue}}
    </div>
</template>
<script>

export default {
    name: 'TestInput'.props: {
        modelValue: String 
    },
    emits: ["update:modelValue"].methods: {
        fun() {
            this.$emit("update:modelValue"."Hello 123!")}}}</script>
Copy the code

2, the realization of the principle

Implementation of computed attributes:

(1) the parent component

<template>
    <div>
        <p>Use v-Models on components</p>
        {{textComponent}}
        <! Principle of -- -- -- >
        <test-input :modelValue="textComponent" @update:model-value="textComponent = $event" />
    </div>
</template>
<script>
import TestInput from './TestInput.vue'

export default {
    name: 'index'.components: {
        TestInput

    },
    data() {
        return {
            textComponent: "Hello!}}},</script>
Copy the code

(2) the child components

<template>
    <div>
        <! -- <input type="text" :value="text" @input="fun"> -->
        <! -->
        <input type="text" :value="text" @input="fun">
    </div>
</template>
<script>

export default {
    name: 'TestInput'.props: {
        modelValue: String 
    },
    emits: ["update:modelValue"].computed: {
        text: {set(e){
                this.$emit("update:modelValue", e.target.value)
            },
            get(){
                // props was passed in
                return this.modelValue
            }
        }
    },
    methods: {
        fun(e) {
            this.$emit("update:modelValue", e.target.value)
        }
    },
}
</script>
Copy the code

3. Bind multiple

(1) the parent component

<template>
    <div>
        <p>Use v-Models on components</p>
        {{textComponent}}
        <br />
        {{title}}
        <! -- bind multiple,v-model: name -->
        <test-input v-model="textComponent" v-model:title="title" />
    </div>
</template>
<script>
import TestInput from './TestInput.vue'

export default {
    name: 'index'.components: {
        TestInput

    },
    data() {
        return {
            textComponent: "Hello!.title: "Hehe hehe"}}},</script>
Copy the code

(2) the child components

<template>
    <div>
        <! -- Pass multiple values, different display -->
        <input type="text" v-model="text">
        <input type="text" v-model="title1">
    </div>
</template>
<script>
export default {
    name: 'TestInput'.props: {
        modelValue: String.title: String
    },
    / / event
    emits: ["update:modelValue"."update:title"].computed: {
        text: {set(e){
                this.$emit("update:modelValue", e)
            },
            get(){
                // props was passed in
                return this.modelValue
            }
        },
        // The calculation properties and props names cannot be the same
        title1: {set(e){
                this.$emit("update:title", e)
            },
            get(){
                // props was passed in
                return this.title
            }
        },

    }
}
</script>
Copy the code