Component pass value - slot - props - dynamic class

7.11 Summary

1. Virtual DOM

  • Through the js object structure, a data form that simulates the html tag structure, it is not a tag element, but the structure is similar to the tag element structure, virtual DOM only operates on data objects, and has nothing to do with page views, so the efficiency of virtual DOM execution More efficient than real DOM execution

Simply put, when we use vue to render the label, vue will first create a virtual dom object, which is actually the same as the real dom

When we need to manipulate dom to render data, we create a new virtual dom, compare the new virtual dom with the old virtual dom, and use the diff algorithm to render different data to the page.

2. Introduction to vue components

  • what is a component

Components are the basic components of a vue project, which are divided into three types: root components, global components, and local components. A vue project must have at least one component, which is the root component (new Vue()), and other components can be added as needed

  • How to create components

Root component: use new Vue to create vue objects by default

Global components: In the global scope, components defined using Vue.component() can be used in the global scope

Local component: a component defined using the components field inside a component can only be used in the component where it is located

  • Configure components
      // component register component
      Vue.component("myCom1",{
            // You can use the name property to configure the name of the specified component to render in the developer tools
             name: "ztp",
            // The root component's el binding component is a template binding
            // template will replace everything in #app
            template: "<h4>This is the global component template{{ age }}</h4>",
            // In the root component, data is directly an object, and in global and local data is a function return object. The rest are the same. All fields in the root component will have
            data() {
                return {
                    age: 20
                }
            },
            methods: {},
        })
  • How to use components

There will be a component name after the component definition, just call the component name as the tag name (you can think of the component as a custom tag added by vue to h5)

Note: Components can be defined in lowercase or small camel case, but when using components, use "-" to convert small camel case to lowercase

     // use components
     <div id="app">
     // Use global components ----> because the component name is named myCom1 in small camel case, so use - to write separately
     <my-com1></my-com1>
     // local component usage
     <my-com2></my-com2>
     </div>

     // Can be used in scaffolding Single tag (closed tag) can be used directly
     <my-com2/>
     // This is the root component
     new Vue({
            el: '#app',
            data: {},
            // Define local components in it ----------------------------------------
            components: {
                // The key is the component name: the value is the component configuration information
                myCom2: {
                    template: "<h4>This is the partial component template</h4>",
                    data(){
                        return {}
                    },
                    mathods: {},
                }
            }
        })



        //  This is a global component ---------------------------------------------
        // myCom1 is the defined component name
        Vue.component("myCom1",{
            template: "<h4>This is the global component template{{ age }}</h4>",
            // In the root component data is the object, in the global and local data is the function return object
            data() {
                return {
                    age: 20
                }
            },
            methods: {},
            filters: {},
        })
  • Why use components

Often the data and functions in a project are cumbersome. If they are written in the component, it will be very bloated, which is not conducive to post-maintenance and debugging.

At this time, components are used to split a project into multiple modules, each module is implemented with a component, and finally the code can be separated, making the structure clearer and facilitating later maintenance and updates

If a project has many duplicate modules, such as the carousel navigation bar, which are used in multiple pages, you can package this duplicate function module into a components middle. When using, you can directly call components to implement Code reuse, reduce code size, simplify projects

3. Component template

  • The template of the component can be simply understood as the place to write the component code
       // The component is written in div#app
       <template id="myTem">
            // The global or local components are written in the first tag element under the template 
            <div>
                <button @click="count++">button{{ count }}</button>
            </div>
            <!-- There can only be one root tag in the component template, otherwise an error will be reported -->
            <!-- <div></div> -->
        </template>

 // This kind of understanding is not commonly used 
   <script type="text/html" id="">
        <div>


        </div>
    </script>

4. Component special label rendering —> is property

  • Some illegal tag structures in html cannot be rendered normally, such as:

p tag nested div

a tag nested a

button nested button

section nested section

        <table>
            <tr>tr can be rendered normally to table middle</tr>

            // my-com is the name of a component we defined ---> myCom
            <my-com>Component cannot render to table middle, because the component is not table Identify, will be moved out when rendering</my-com>

            // By binding the is property, this problem can be solved
            // is to turn this tr tag into our component
            <tr is="my-com">table can identify tr,just write tr pass is attribute put tr Render as the specified component, to render the component to table middle</tr>
        </table>

Summary: The is attribute can render the native h5 tag into a specified component to avoid abnormal tag structure rendering

5. Dynamic Components

  • scenes to be used

When we have multiple components, but we don't want to display them all at once, but conditionally display them

    1. Use v-if to judge
    1. Use the is attribute
// Suppose we have three global components that we want to display conditionally
Vue.component('mainCom', { template: '<h1>this is the home page</h1>'});
Vue.component('loginCom', { template: '<h1>This is the login page</h1>'});
Vue.component('userCom', { template: '<h1>This is the user page</h1>'});

// Scheme 1: v-if judgment-------------------------------------------------------------------
// define a variable in global data
data: {
    page: 1
}
// Click to change the page value
<button @click="page='1'">Home</button>
<button @click="page='2'">Log in</button>
<button @click="page='3'">user</button>
// Then judge and display by the value of page
<main-com v-if="page===1"></main-com>
<login-com v-if="page===2"></login-com>
<user-com v-if="page===3"></user-com>


// Option 2: Use the is attribute -------------------------------------------- -----------------------
// Also define a variable in data
data: {
    page: 'mainCom'
},
// Click to replace page with component name
<button @click="page='mainCom'">Home</button>
<button @click="page='loginCom'">Log in</button>
<button @click="page='userCom'">user</button>
// Then a line of code calls
<component :is="page"></component> 

Summary: The is attribute can dynamically render the name of a component, and switch components by switching the name of the component

6. keep-alive keeps component data state

  • When the dynamic component is switched, the component will be destroyed and rebuilt, and the data in the component will also be reset
  • If you want to preserve the data state of the component when the component is switched, you can use keep-alive to wrap the component
we are giving the component input When entering content, When components are switched, will be destroyed. Sometimes we don't want this data to be destroyed,but keep
 then:

// Example from the previous section
// In this way, after wrapping, the component will retain the array state when switching.
<keep-alive>
     <component :is="page"></component>
</keep-alive>
be careful:
when the component is in keep-alive Medium The destruction cycle function of the component declaration cycle will not be executed 
will execute activated(show) and deactivated(hide) Hook functions outside of these two declaration cycles


when the component is not keep-alive The destruction cycle function will be executed only in, rather than go activated(show) and deactivated(hide)

7. Pass value between components - parent to child - slot to pass value

  • Using another component in one component will result in a parent-child relationship between components
  • If the parent component has some data and wants to get the child component to display, it needs to use the component pass-by-value (component communication) to achieve
// root component template ---> parent
<div id="app">
    // We want to use array arr from parent component in child component
    <my-com v-for="item in arr">
         <h1>{{ item }}</h1>    // This h1 replaces the slot, which is rendered in the child component's template
    </my-com>

    // Because when using this component, no code is passed in, so the button button is displayed
    <my-com></my-com>
</div>


// global component template ----> child
<template id='myTem'>
     // This div is the equivalent of the label of the child component div#app in the root component
     <div>
        // Use the slot tag to define a slot. This slot is used to use the data in the parent component.
        <slot></slot>

        // We can also set a default value for the slot in advance, what does it mean?
        // When using the component in the parent component, if no code is written, the button will be displayed
        <slot><button>button</button></slot>
     </div>
</template>


// Global Components ---> Subcomponents
Vue.component('myCom', {
    template: '#myTem',
         data() {
             return {}
         }
})

// root component ---> parent component
new Vue({
    el: '#app',
    data: {
        // This array is to be used in child components
        arr: ["A","B","C"],
    },
})

8.slot slot —> named slot

  • In the last section, we said that if you write some code in advance in the slot, if you do not write the code when using the slot in the parent component, the code in the slot will be displayed by default.
  • But there is a problem
  • That is, when using a component multiple times, we don't want every component to display this default value
  • At this time, we can add a name attribute to this slot and attach a value
  • When used in the parent component, add a slot attribute and assign the value of the name attribute to the slot
  • In this way, when writing code in the parent component, only the default label with the name attribute and the value corresponding to it will be replaced.
// parent component
<div id="app">
    // Only the label in the component with name = "center" is replaced,
    <cpn><button slot="center">title</button></cpn>
 </div>
// Subassembly
<template id="cpn">
    <div>
      <slot name="left"><span>left</span></slot>
      <slot name="center"><span>middle</span></slot>
      <slot name="right"><span>right</span></slot>
      <slot>hahahahaha</slot>
    </div>
 </template>

// When running the code at this time, we will find that the displayed result is:
Case 1:  if put slot middle name delete all attributes, and when using slot attribute is also removed, The result of running the code is:
title title title title  --->  three slot The values ​​in the labels are all replaced

Case 2: if given each slot add a tag name Attributes, and have a different name,giving slot append a value, The result of running the code is:
left title right hahahaha  ---> we can find out that, only name properties and slot The middle corresponding to the attribute is replaced, The rest are not replaced


9. v-slot

  • If multiple labels are given when the slot is labelled in the parent component
  • Then, a slot attribute must be specified in each label to specify which slot is inserted.
  • Here's a trick
  • Use the <template> tag, wrap it. Because this tag will not be rendered out of the real DOM
  • But change the slot attribute to v-slot
  • It only needs to be written once

9. Scope slot ----> child to parent

  • Compile scope:

What is compile scope?

That is, things in the parent template can only be used in the parent scope

Things in child templates can only be used in child scopes

  • In the slots in the previous sections, the data in the parent component is often used in the child component

  • If there is a data in the child component, we want to use it directly in the parent component, or we are not satisfied with the rendering effect of this child component

  • how should I do it?

  • Use on slot, : + variable name to send out data

  • When the parent component uses the child component, use the slot-scope attribute on the template tag to receive the data from the child component

  • Then you can use it directly!!!

<div id="app">
    <!-- <cpn></cpn> -->

    <cpn>
      // 2. Use the slot-scope property here to receive data from :data
      // The purpose is to get the planguages ​​in the subcomponents, those below vue2.5.x must use the template above, there is no requirement
      // slot-scope is a fixed way of writing to receive data from the slot
    
      <template slot-scope="slot">
        // 3. Then just use it directly!!! -->
        // <span v-for="item in slot.data">{{item}} - </span> 
        <span>{{slot.data.join(" - ")}}</span>
      </template>

    </cpn>
  </div> 

  <template id="cpn">
    <div>
      // 1. Send data here
      <!-- :data Outgoing data can not be called data name yourself -->
      <slot :data="planguages">
        <ul>
          <li v-for="item in planguages">{{ item }}</li>
        </ul>
      </slot>
    </div>
  </template>
  <script>
    // father
    new Vue({
      el: '#app',
      data: {
        message: "Hello"
      },
      components: {
        // son
        cpn: {
          template: "#cpn",
          data() {
            return {
              planguages: ['java', 'javaScript', 'C++', "Python", "Go"]
            }
          }
        }
      }
    })
  </script>

10. Passing values ​​between components —> parent-child-props passing values

  • props are custom properties in vue, vue puts all custom property values ​​in props
// root component template ---> parent
<div id="app">
    // We want to use array arr from parent component in child component 
    // The operation of this step is to pass the value to the custom attribute name in the child component ---> myArr
    <my-com v-for="(item,i) in arr" :my-arr="item" :key="i"></my-com>
</div>


// global component template ----> child
<template id='myTem'>
     // This div is the equivalent of the label of the child component div#app in the root component
     <div>
        // myArr is our custom attribute name
        // ---> Now myArr holds the value in item Our code is written inside the child component <---
        <h2>{{ myArr }}</h2>
     </div>
</template>


// Global Components ---> Subcomponents
Vue.component('myCom', {
    template: '#myTem',
         data() {
             return {}
         },
         // and data level, you can define multiple
         // props can also be an object, if it is an object, it can define what type of data must be passed
         props: ["myArr"],
    
         props: {
             // The advantage of writing as an object 1: You can limit the type
             // If it is multiple types ---> use array [String, Number]
             myArr: Array,  // Indicates that what is passed to myArr must be an array type
             
             
             // Benefit 2: Provide some default values
             myArr: {
                // type
                type: String,
                // The default value is aaa The default value only takes effect when no value is passed
                // If the default value is an array or object, it must be in the form of a function ---> return out []/{}
                default: 'aaaaa',
                // Indicates that a value must be passed when using the custom attribute myArr
                required: true,
             }
         }
})

// root component ---> parent component
new Vue({
    el: '#app',
    data: {
        // This array is to be used in child components
        arr: ["A","B","C"],
    },
})
  • Summarize
  1. The steps to pass the value of props are cumbersome and the operation is complicated. The value of slot is simple and convenient
  2. The data passed by props can be called in the child component object. The data passed by slot can only be displayed and cannot be called
  3. The biggest difference between the two is: the slot value is written in the parent component template, and the props custom attribute value is written in the child component itself!!!

11. How does props implement child-to-father?

    1. When binding a custom property of a child component, instead of giving a data, give a method
    2. Called after getting the method using the custom attribute in the child component
    3. By calling the function, it is passed to the called function in the form of a parameter
    4. In this way, the data in the child component is obtained in the parent component
    5. In this way, the child-to-parent effect of props can be achieved!

12. Dynamic binding class

        // The value is false to show true to hide
        // 1. Both dynamic binding class es and non-dynamic ones can coexist
        <div class="fw" :class="{fs:flag}">Zhang San</div>

        // 2. You can bind multiple dynamic class es at a time
        <div class="fw" :class="{fs:flag,red:flag}">Li Si</div>

        // 3. You can write the class name and style first, and then add it dynamically ---> unnecessary 
        <div :class="cla">Wang Er</div>

        // 4. It can be written in the form of an object, and the key-value pair of the object is the class name
        // You can also put objects directly in this
        <div :class="classObj">pock</div>

        // 5. Can write simple judgments
        <div :class="10>20?'fs':'fw'">little king</div>

        // 6. You can use an array to pass multiple at a time
        <div :class="[claFw,claFs]">little red</div>


        // pre-defined css styles
        .red{
            background-color: red;
        }
        .fs{
            font-size: 32px;
            background-color: green;
        }
        .fw{
            font-weight: bold;
        }

        // Contrast the above
        data: {
                flag: false,
                cla: "red",
                classObj: {
                    "red":false,
                    "fw": true
                },
                claFw: "fw",
                claFs: "fs",
                
            },

13. Dynamic binding style

        // native js binding
        <div style="background-color:red;color:green;">Zhang San</div>
        // dynamic binding
        <div :style="styleObj1">Li Si</div>
        // bind multiple
        <div :style="[styleObj1,styleObj2]">Wang Er</div>
        // bind as an object
        <div :style="{backgroundColor:red,color:redss}">pock<div>
        <div :style="{'background-color':red,'color':redss}">aaaaa</div>


        data: {
                styleObj1: {
                    backgroundColor: 'red',
                    color: 'green'
                },
                styleObj2: {
                    fontSize: '32px'
                },
                red: "#FF0000",
                redss: "green"
         },

14. Access data —> parent access child

14.1 $children & $refs

$children

  • If you want to get the data of the child component in the parent component, just use this.$children in the parent component
  • this.$children is an array type of data, there are several child components in the parent component, and there are several values ​​in the array
  • so:
  • When we get the value, we need to use the index to get the value
  • When we call multiple sub-components, if other components are added in the middle, the index will change, which brings great inconvenience!!!

$refs

  • $refs is an empty object by default, which can only be found after adding the ref attribute to the component
  • Using this, no matter how the order of the subcomponents changes, we can get it.
<div id="app">
        <cpn ref="aaa"></cpn>
        <cpn></cpn>
        <cpn></cpn>
        <button @click="btnClick">button</button>
    </div>
    <template id="cpn">
        <div>I am a child component</div>
    </template>
    <script>
        new Vue({
            el: '#app',
            data: {
                message: 'Hello',
            },
            methods: {
                btnClick() {
                    
                    // 1. this.$children is an array type of data, there are several values ​​in the array of several child components
                    // This method is not commonly used: 
                    // Because the value is obtained by index, when we add other subcomponents in the middle of subcomponents, the index will send changes. It brings great inconvenience.
                    console.log(this.$children);
                    for (const c of this.$children) {
                        console.log(c.name);
                        c.showMessage();
                    }

                    // 2. $refs is an empty object by default and can only be found by adding ref to the component
                    // Using this, no matter how the order of subcomponents changes, you can get it
                    console.log(this.$refs.aaa);
                    console.log(this.$refs.aaa.name);
                    
                }
            },
            components: {
                cpn: {
                    template: "#cpn",
                    data (){
                        return {
                            name: 'I am in the child component name'
                        }
                    },
                    methods: {
                        showMessage() {
                            console.log('showMessage');
                        }
                    },
                }
            }
        })
    </script>

15. Component access data -> child access parent

15.1 $parent & $root

$parent

  • You can use $parent directly in the child component to get the data in the parent component,
  • but!!!
  • It is not recommended to use this way
  • Because once used in this way, the self-component is not independent enough, the reusability is greatly reduced, and the coupling with the parent component is too high

$root access to root components

  • You can use this to access root component data
  • But it is used very rarely
  • Because there is nothing in the general root component
<div id="app">
        <cpn></cpn>
</div>
<template id="cpn">
    <div>
        <h2>I'm cpn components</h2>
        <ccpn></ccpn>
    </div>

    </template>
    <template id="ccpn">
        <div>
            <h2>I am a child component</h2>
            <button @click="btnClick">button</button>
        </div>
    </template>
    <script>
        new Vue({
            el: '#app',
            data: {
                message: 'Hello'
            },
            components: {
                cpn: {
                    template: "#cpn",
                    data() {
                        return {
                            name: 'I'm cpn component name'
                        }
                    },
                    components: {
                        ccpn: {
                            template: "#ccpn",
                            methods: {
                                btnClick() {
                                    // 1. Access the parent component
                                    // console.log(this.$parent);
                                    // console.log(this.$parent.name);
                                    // But it is not recommended to use this way, because once used, the child components are not independent enough, the reusability is greatly reduced, and the coupling with the parent component is too high

                                    // 2. Access the root component $root
                                    // It is also used very little
                                    // Because there is generally nothing in the final vue instance
                                    console.log(this.$root);  // vue instance
                                    console.log(this.$root.message);
                                }
                            },
                        }
                    }
                }
            }
        })
    </script>

Tags: Javascript Front-end Vue.js

Posted by ArmanIc on Wed, 31 Aug 2022 22:08:59 +0300