Create flexible and reusable web applications: Vue component development guide!


1. Introduction to components

1.1. Official concept

Components are one of the most powerful features of Vue. Components can extend HTML elements,Encapsulate reusable code. At a high level, components arecustom element, Vue's compiler adds special features to it. In some cases, components can also appear as is特性native HTML elements extended with .

​ Vue allows us to use independent reusable small components to build large-scale applications, and any type of application interface can be abstracted into a component tree.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-1ugvqRms-1690870417749)(/004.webp)]

All Vue components are also instances of Vue, so can accept the same options object.

1.2. Briefly introduce the is feature

​ In layman's terms, for example, some elements, such as ulcan only contain lielements directly, selectcan only contain option, and tablecan only contain tr, td, tbodyand so on. For example like this:

<ul>
    <li></li>
    <li></li>
</ul>

​ There is no problem with this way of writing, and the browser can parse it correctly, but if you want to do this, the browser will not understand it, such as the following:

<ul>
    <my-li></my-li>
    <my-li></my-li>
</ul>

​ In this way, this kind of label cannot be used my-li. If we want to achieve our goal, we need to use isfeatures. Like this, where the value of the is attribute is the component name:

<ul>
    <li is="my-li"></li>
    <li is="my-li"></li>
</ul>

1.3, the difference between componentization and modularization

Components and modules are positioned differently. Components are generally used in the front end, and modularization is used more in the background. For example, the components in vue are mainly to split the code volume of the vue instance, so that we can use different components to divide different functional modules. What kind of functions we need in the future, we can directly call the corresponding components.

​ Modules in modularization generally refer to Javascript modules

​ The component contains template, style and script, and its script can be composed of various modules. It can also be understood as a "framework", which means dividing functions and integrating the same type of code. Componentization is equivalent to making a page, splitting each independent function in the page, you can split it as much as you want, and finally assemble it into a complete page.

  • Componentization

    ​ Mainly divided from the UI interface. For example, the componentization of the front end facilitates the calling of ui components. Similar to the previous navigation bar.

  • Modular

    ​ It is mainly divided from the perspective of code logic to facilitate layered development of code and ensure that each functional module has a single responsibility.

2. A simple HelloWorld case

2.1. Steps to use components

  • Create component constructor
  • register component
  • use components

2.2. Case

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component></my-component>
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        // 1、创建组件构造器
        const myComponent = Vue.extend({
      
      
            template: `
                    <div>
                        <h1>爱学习的少年</h1>
                        <p>HelloWorld</p>
                        <p>HelloWorld</p>
                    </div>
                    `
        });

        // 2、注册组件
        Vue.component("my-component",myComponent);

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

3. Create global components

3.1. Method 1

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component></my-component>
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        // 1、创建组件构造器
        const myComponent = Vue.extend({
      
      
            template: `							// 模板只能有一个而且只能有一个根元素
                    <div>
                        <h1>爱学习的少年</h1>
                        <p>HelloWorld</p>
                        <p>HelloWorld</p>
                    </div>
                    `
        });

        // 2、注册组件【注意:如果使用的是驼峰命名,则在使用组件的时候需要使用'-'连接】
        Vue.component("myComponent",myComponent);

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

3.2. Method 2

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component></my-component>
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        // 1、直接使用Vue.component创建组件
        Vue.component("myComponent",{
      
      
            template: `
                    <div>
                        <h1>爱学习的少年</h1>
                        <p>HelloWorld</p>
                    </div>
                    `
        });
        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

3.3. Method 3

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component></my-component>
    </div>

    <template id="myTemplate">
        <div>
            <h1>爱学习的少年</h1>
            <p>Spring</p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        // 1、引入外部一个模板片段
        Vue.component("myComponent",{
      
      
            template: "#myTemplate"
        });
        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

3.4. Method 4

<body>
    <div id="myDiv">
        <my-component></my-component>
    </div>

    <script type="text/x-template" id="myTemplate">
        <h1>使用script实现注册组件</h1>
    </script>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 注册组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate"
        });

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

4. Create private components

4.1. Method 1

<body>
    <div id="myDiv">
        <my-nav></my-nav>
        <my-nav></my-nav>
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        const app = new Vue({
      
      
            el: "#myDiv",
            components: {
      
      
                myNav: {
      
      
                    template: "<h1>这个是导航条,私有组件</h1>"
                }
            }
        });
    </script>
</body>

4.2. Method 2

<body>
    <div id="myDiv">
        <my-nav></my-nav>
        <my-nav></my-nav>
    </div>

    <template id="myTemplate">
        <h1>这个是导航条,私有组件</h1>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        const app = new Vue({
      
      
            el: "#myDiv",
            components: {
      
      
                myNav: {
      
      
                    template: "#myTemplate"
                }
            }
        });
    </script>
</body>

5. Component filling data

5.1. Description

  • The component is actually an instance object of Vue, and it can also have its own data, but the value of the data here is afunction, and the function must return aObject object
  • data is used in exactly the same way as before.

5.2. Case

<body>
    <div id="myDiv">
        <my-nav></my-nav>
        <my-nav></my-nav>
    </div>

    <template id="myTemplate">
        <h1>用户名是: {
   
   {username}}</h1>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component("my-nav",{
      
      
            template: "#myTemplate",
            data: function(){
      
      
                return {
      
      username: 'HelloWorld'}
            }
        });
        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

5.3. Discuss why the data value is a function instead of an object

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component></my-component>
        <my-component></my-component>
    </div>

    <template id="myTemplate">
        <div>
            计数器: {
   
   {count}} <br/>
            <button @click="count++">+</button>
        </div>
    </template>


    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 注册组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function () {
      
      
                console.log("--"); // 打印了3次
                return {
      
      count: 0}
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

6. Component switching

6.1. Method 1: Use v-if to judge

<body>
    <div id="myDiv">
        <a href="" @click.prevent="login">登录</a>
        <a href="" @click.prevent="register">注册</a>

        <login v-if="isLogin"></login>
        <register v-else></register>

    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component("login",{
      
      
            template: `
                <div>
                    用户名登录: <input type="text" placeholder="用户名登录"/>
                </div>
            `
        });

        Vue.component("register",{
      
      
            template: `
                <div>
                    用户名注册: <input type="text" placeholder="用户名注册"/>
                </div>
            `
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                isLogin: true
            },
            methods: {
      
      
                login(){
      
      
                    this.isLogin = true;
                },
                register(){
      
      
                    this.isLogin = false;
                }
            }
        });
    </script>
</body>

6.2. Method 2: implementation of is

<body>
    <div id="myDiv">
        <a href="" @click.prevent="componentName = 'login'">登录</a>		// 记得加单引号
        <a href="" @click.prevent="componentName = 'register'">注册</a>	// 记得加单引号

        <component :is="componentName"></component>

    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component("login",{
      
      
            template: `
                <div>
                    用户名登录: <input type="text" placeholder="用户名登录"/>
                </div>
            `
        });

        Vue.component("register",{
      
      
            template: `
                <div>
                    用户名注册: <input type="text" placeholder="用户名注册"/>
                </div>
            `
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                componentName: "login"
            }
        });
    </script>
</body>

Seven, parent and child components

7.1. Preliminary understanding of the definition of parent-child components

<body>
    <div id="myDiv">
        <father></father>
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 1、定义子组件
        const children =  Vue.extend({
      
      
            template: `
                <h1>这个子组件</h1>
            `	
        });

        // 2、定义父组件
        const father = Vue.extend({
      
      
            template: `
                <div>
                    <h2>这个是父组件</h2>
                    <children></children>
                </div>
            `,
            components: {
      
      
                children
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            components: {
      
      
                father
            }
        });
    </script>
</body>

7.2. Parent components pass data to child components

7.2.0, problem case

<body>
    <div id="myDiv">
        <my-component></my-component>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                username: "HelloWorld"
            },
            components: {
      
      
                myComponent: {
      
      
                    template: '<h1>姓名是: {
      
      {username}}</h1>' // 会报错
                }
            }
        });
    </script>
</body>
// 按道理来说,子作用域应该可以访问父级别作用域的,但是发现并不行。

​The solution

Method: pass data to subcomponents through props

7.2.1. Form 1

​String array, the strings in the array are the names when passing.

​ Description: Let the instance of Vue be the parent component, and then define a child component

<body>
    <div id="myDiv">
        <my-component v-bind:subusername="username"></my-component>
    </div>
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        const app = new Vue({
            el: "#myDiv",
            data: {
                username: "HelloWorld"
            },
            components: {
                myComponent: {
                    props: ['subusername'],
                    template: '<h1>姓名是: {
   
   {subusername}}</h1>'
                }
            }
        });
    </script>
</body>
<body>
    <div id="myDiv">
        <my-component v-bind:subaddresses="fatherAddresses"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            <p v-for="item in subaddresses">
                {
   
   {item}}
            </p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 注册组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: ["subaddresses"]
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                fatherAddresses: [
                    '河南林州',
                    "陕西西安",
                    "浙江杭州"
                ]
            }
        });
    </script>
</body>

The parent component needs to pass data to the child component, which is summarized as follows:

  • first step:

    ​ When the parent component applies the child component, dynamically bind a property.

    <my-component v-bind:subusername="username"></my-component>
    

    ​Thissubusername attribute is a custom attribute name, the purpose is to pass such a name of data to the subcomponent. It usernameis the data in the parent component data.

  • Step two:

    ​ After the custom attribute is completed, the subcomponent cannot be used directly, but needs to be received. subusernameThat is: the attribute passed from the parent component needs propsto be defined in the array of the child component. Note that it is in the form of a string, so that the child component can use this data.

    ​ It can also be said that the data defined in all props in the component is passed to the child component through the parent component.

  • third step:

    ​ The subcomponent templateuses the name defined by the subcomponent in props, and the data can be used.

Explain a few details:

  • For subcomponents, they can also have their own dataproperties, that is to say, subcomponents can have their own data, and datathe data in them is not passed through the parent component, but unique to the subcomponent itself, a commonly used method Yes: Subcomponents can request data by calling ajax, and then fill the queried data into dataattributes. The properties of the child component propsmust be passed from the parent component.
  • dataThe data in the attribute is readable and changeable, while propsthe data in the attribute is read-only.

7.2.2. Form 2

​Object , the object can set the type when passing, or set the default value

<body>
    <div id="myDiv">
        <my-component v-bind:subaddresses="fatherAddresses"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            <p v-for="item in subaddresses">
                {
   
   {item}}
            </p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 注册组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: {
      
      
                subaddresses: Array  // 对象,可以指定类型
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                fatherAddresses: [
                    '河南林州',
                    "陕西西安",
                    "浙江杭州"
                ]
            }
        });
    </script>
</body>
  • Specify default value: basic type

    <body>
        <div id="myDiv">
            <my-component v-bind:subusername="fatherUsername"></my-component> // HelloWorld
            <my-component></my-component>					//使用组件没有传,就用默认的值
        </div>
    
        <template id="myTemplate">
            <div>
               {
         
         {subusername}}
            </div>
        </template>
    
        <script src="../js/vue.js"></script>
        <script type="text/javascript">
    
            // 注册组件
            Vue.component("myComponent",{
            
            
                template: "#myTemplate",
                props: {
            
            
                    subusername: {
            
            
                        type: String,
                        default: "Spring"
                    }
                }
            });
    
            const app = new Vue({
            
            
                el: "#myDiv",
                data: {
            
            
                    fatherUsername: "HelloWorld"
                }
            });
        </script>
    </body>
    
  • Specify default value: object or array

    <body>
        <div id="myDiv">
            <my-component v-bind:subaddresses="fatherAddresses"></my-component>
            <my-component></my-component>
        </div>
    
        <template id="myTemplate">
            <div>
               <p v-for="item in subaddresses">{
         
         {item}}</p>
            </div>
        </template>
    
        <script src="../js/vue.js"></script>
        <script type="text/javascript">
    
            // 注册组件
            Vue.component("myComponent",{
            
            
                template: "#myTemplate",
                props: {
            
            
                    subaddresses: {
            
            
                        type: Array,
                        default: function(){
            
            
                            return ['HelloWorld' , "Spring"];	// 对象或数组默认值的话要用函数
                        }
                    }
                }
            });
    
            const app = new Vue({
            
            
                el: "#myDiv",
                data: {
            
            
                    fatherAddresses: [
                        "河南林州",
                        "浙江杭州"
                    ]
                }
            });
        </script>
    </body>
    
  • Specify whether to pass

    <body>
        <div id="myDiv">
            <my-component v-bind:subusername="fatherUsername"></my-component>
            <my-component></my-component>       // 会报错,要必传才行
        </div>
    
        <template id="myTemplate">
            <div>
               {
         
         {subusername}}
            </div>
        </template>
    
        <script src="../js/vue.js"></script>
        <script type="text/javascript">
    
            // 注册组件
            Vue.component("myComponent",{
            
            
                template: "#myTemplate",
                props: {
            
            
                    subusername: {
            
            
                        type: String,
                        required: true  // 表示必传
                    }
                }
            });
    
            const app = new Vue({
            
            
                el: "#myDiv",
                data: {
            
            
                    fatherUsername: "HelloWorld"
                }
            });
        </script>
    </body>
    

7.2.3. Improvement in wording: camel case

<body>
    <div id="myDiv">
        <my-component v-bind:sub-addresses="fatherAddresses"></my-component>// 标签需要"-"连接
        <my-component></my-component>
    </div>

    <template id="myTemplate">
        <div>
           <p v-for="item in subAddresses">{
   
   {item}}</p>		// 拿数据依然是驼峰法方式
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 注册组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: {
      
      
                subAddresses: {
      
      				// 驼峰命名
                    type: Array,
                    default: function(){
      
      
                        return ['HelloWorld' , "Spring"];
                    }
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                fatherAddresses: [
                    "河南林州",
                    "浙江杭州",
                    "云南大理"
                ]
            }
        });
    </script>
</body>

7.3. Subcomponents pass data to parent components

Method: send a message to the parent component through a custom event

<body>
    <div id="myDiv">
        <my-component @fn="fatherFn"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            <button @click="subCompClick">子组件向父组件传递参数使用的事件的方式</button>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 定义子组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function(){
      
      
                return {
      
      
                    person: {
      
      
                        username: '我是子组件HelloWorld'
                    }
                }
            },
            methods: {
      
      
                subCompClick(){
      
      
                    // 点击之后,子组件发射一个自定义的事件
                    this.$emit("fn",this.person);
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                username: "HelloWorld"
            },
            methods: {
      
      
                fatherFn(obj){
      
      
                    console.log(obj);
                }
            }
        });
    </script>
</body>

​The idea of ​​solution [Actually, although we are indeed talking about passing data from child components to parent components, it is not easy to understand if we want to implement the code according to this way of thinking. I personally recommend this way of understanding, that is: don’t consider it now We always regard the child component to pass data to the parent component as: the parent component passes data to the child component. If we understand it in this way, writing code will be much smoother. To understand the code in this way, write When it is written, it will naturally become that the child component passes data to the parent component. ==

​The child component passes data to the parent component/the parent component passes the method to the child component, the steps are summarized as follows:

  • first step

    ​ Define a method in the parent component. In this case, the Vue instance is used as the parent component, and the custom method is fatherFn.

  • second step

    ​ On the label of the application subcomponent, dynamically bind an event. The event in this case is fn.

    <my-component @fn="fatherFn"></my-component>
    

    fatherFn​ The meaning of the code: it is equivalent to passing the reference of the method in the parent component to fnthe event function of the child component. At this time, the fnfunction must be used at some point.

  • third step

    ​ Since we are passing data from the child component to the parent component, we must have done some operations in the child component and then passed the data to the parent component. In this case, templatethere is a buttonbutton in the child component, and the function of the button is to pass data to the parent component when clicked. And an event is bound to the button, the event that belongs to the button, yes subCompClick.

  • the fourth step

    methods​ Define the event in the properties of the subcomponent subCompClick, which will be triggered when the button is clicked, then in

    subCompClickIn the event, the operation is: call $emitthe method to emit our fnevent, and pass the data through the method, and we know that ours fnis actually the one in our first step fatherFn. Then in fatherFnthe function, the data passed by the sub-component can be received in the form of parameters.

<body>
    <div id="myDiv">
        <my-component v-on:get-list-click="fatherHandle"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            <a href=""
               v-for="item in categories"
               @click.prevent="aClick(item)">
                {
   
   {item.name}} <br>
            </a>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        // 子组件
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function(){
      
      
                return {
      
      
                    categories: [
                        {
      
      id: 1, name: "动作片"},
                        {
      
      id: 2, name: "爱情片"},
                        {
      
      id: 3, name: "悬疑片"},
                        {
      
      id: 4, name: "悬疑片"}
                    ]
                };
            },
            methods: {
      
      
                aClick(item){
      
      
                    // 点击之后,子组件发射一个自定义的事件
                    this.$emit("get-list-click",item);
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            methods: {
      
      
                fatherHandle(item){
      
      
                    console.info("接收的信息是:" ,item);
                }
            }
        });
    </script>
</body>

7.4. Case

​This case: the comprehensive application of data transmission from child components to parent components. This case is a case of our second phase of jQuery: the case of posting comments.

7.4.1. The first step: first simulate the data

<body>
    <div id="myDiv">
        <p v-for="item in list" :key="item.id">
            评论人: {
   
   { item.user }} 内容: {
   
   { item.content }} 发表日期: {
   
   { item.pubDate }}
        </p>
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                list: [
                    {
      
      id: 1, user: 'HelloWorld', content: '美好的一天', pubDate: new Date()},
                    {
      
      id: 2, user: 'Spring', content: '很高兴', pubDate: new Date()}
                ]
            }
        });
    </script>
</body>

7.4.2. The second step: define subcomponents and post comments

<body>
    <div id="myDiv">
        
        <my-component></my-component>

        <p v-for="item in list" :key="item.id">
            评论人: {
   
   { item.user }} 内容: {
   
   { item.content }} 发表日期: {
   
   { item.pubDate }}
        </p>
    </div>

    <template id="myTemplate">
        <div>
            评论id: <input type="text"> <br/>
            评论人: <input type="text"> <br/>
            评论内容:<textarea></textarea><br/>
            <input type="button" value="提交">
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                list: [
                    {
      
      id: 1, user: 'HelloWorld', content: '美好的一天', pubDate: new Date()},
                    {
      
      id: 2, user: 'Spring', content: '很高兴', pubDate: new Date()}
                ]
            }
        });
    </script>
</body>

7.4.3. Step 3: Click to post a comment

  • Bind v-model to form control, the purpose is to get data
  • The bound data needs to be defined in the data of the subcomponent template
  • Provide a click event for the post button
<body>
    <div id="myDiv">

        <my-component @fn="fatherFn"></my-component>

        <p v-for="item in list" :key="item.id">
            评论人: {
   
   { item.user }} 内容: {
   
   { item.content }} 发表日期: {
   
   { item.pubDate }}
        </p>
    </div>

    <template id="myTemplate">
        <div>
            评论id: <input type="text" v-model="id"> <br/>
            评论人: <input type="text" v-model="user"> <br/>
            评论内容:<textarea v-model="content"></textarea><br/>
            <input type="button" value="发表" @click="publish">
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data:function(){
      
      
                return {
      
      id: '' , user: '' , content: ''}
            },
            methods: {
      
      
                publish: function(){
      
      
                    // 发表评论业务处理
                    // 1、构造一个评论数据对象
                    let comment = {
      
      id: this.id, user: this.user , content: this.content, pubDate: new Date()};

                    // 2、需要将创建好的评论数据保存到父组件中的data中,涉及到了子组件向父组件传值
                    // >> 子组件发射一个自定义的事件
                    this.$emit("fn",comment);
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                list: [
                    {
      
      id: 1, user: 'HelloWorld', content: '美好的一天', pubDate: new Date()},
                    {
      
      id: 2, user: 'Spring', content: '很高兴', pubDate: new Date()}
                ]
            },
            methods: {
      
      
                fatherFn(comment){
      
      
                    // 刚刚新增评论就插入到数组的头部
                    this.list.unshift(comment);
                }
            }
        });
    </script>
</body>

8. Comprehensive case

Explanation: This case shows that parent and child components pass data to each other.

8.1, the first step: realize the parent component data transfer to the child component

<body>
    <div id="myDiv">
      	父组件的数据:{
   
   {username}} {
   
   {age}}
        <my-component :subusername="username" :subage="age"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            通过props属性获取到的父组件中的数据:{
   
   {subusername}}---{
   
   {subage}}
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: {
      
      
                subusername: String,
                subage: Number
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                username: 'HelloWorld',
                age: 12
            }
        });
    </script>
</body>

​Explanation : Through the case, it can be found that the child component can indeed use the data in the parent component. Subcomponents can use the data in props and display it on the page, but the data in props is obtained from the parent component and is read-only data.

8.2, the second step: look at a detail

​ In the subcomponent, define two input, realize two-way binding, bind to propsthe property subusernameand subagethese two properties, and see the experimental results.

<body>
    <div id="myDiv">
      	父组件的数据:{
   
   {username}} {
   
   {age}}
        <my-component :subusername="username" :subage="age"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            通过props属性获取到的父组件中的数据:{
   
   {subusername}}---{
   
   {subage}} <br/>
            双向绑定props属性中的subusername: <input type="text" v-model="subusername"><br/>
            双向绑定props属性中的subage: <input type="text" v-model="subage"><br/>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: {
      
      
                subusername: String,
                subage: Number
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                username: 'HelloWorld',
                age: 12
            }
        });
    </script>
</body>

Through experiments, it is found that this case is problematic, and the console will report an error.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-UlBrOQmL-1690870417750)(/005.png)]

​Conclusion : According to the prompt, avoid directly modifying the data in the props attribute, because the data in the props attribute is passed through the parent component and is read-only, so avoid overwriting. Instead, you can use data and computed computed properties.

8.3, the third step: use the data attribute

<body>
    <div id="myDiv">
      	父组件的数据:{
   
   {username}} {
   
   {age}}
        <my-component :subusername="username" :subage="age"></my-component>
    </div>

    <template id="myTemplate">
        <div>
            通过props属性获取到的父组件中的数据:{
   
   {subusername}}---{
   
   {subage}} <br/>
          	子组件data属性中的数据:{
   
   {data_subusername}}---{
   
   {data_subage}} <br/>
            双向绑定data属性中的subusername: <input type="text" v-model="data_subusername"><br/>
            双向绑定data属性中的subage: <input type="text" v-model="data_subage"><br/>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: {
      
      
                subusername: String,
                subage: Number
            },
            data: function(){
      
      
                return {
      
      
                    data_subusername: this.subusername,
                    data_subage: this.subage
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                username: 'HelloWorld',
                age: 12
            }
        });
    </script>
</body>

​Use data to solve the problem. But there is another requirement: if I want to change the data of the text box in the child component, I also want to modify it to the parent component synchronously, so that the parent component can also be updated synchronously. In this case, it involves the child component passing data to the parent component, and custom events need to be used.

8.4, the fourth step, set the listener for the data of the subcomponent

​ Requirements: In order to realize that the data of the child component can be passed to the parent component, that is to say, if the data data in the child component changes, the parent component can also perceive it, and a custom event needs to be emitted to solve it. At this point, it can be realized by setting a listener for the attribute in data in the subcomponent. When the attribute is modified, it will be listened immediately and then the event will be sent.

<body>
    <div id="myDiv">
        父组件的数据:{
   
   {username}} {
   
   {age}}
        <my-component :subusername="username" :subage="age"
                      @subchangeusername="fatherChangeUsername"
                      @subchangeage="fatherChangeAge"
        ></my-component>
    </div>

    <template id="myTemplate">
        <div>
            子组件通过props属性获取到的父组件中的数据:{
   
   {subusername}}---{
   
   {subage}} <br/>
            子组件通过data属性获中的数据:{
   
   {data_subusername}}---{
   
   {data_subage}} <br/>
            双向绑定props属性中的subusername: <input type="text" v-model="data_subusername"><br/>
            双向绑定props属性中的subage: <input type="text" v-model="data_subage"><br/>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            props: {
      
      
                subusername: String,
                subage: Number
            },
            data: function(){
      
      
                return {
      
      
                    data_subusername: this.subusername,
                    data_subage: this.subage
                }
            },
            watch: {
      
      
                data_subusername(newValue){
      
      
                    // 发生了修改,发送事件
                    this.$emit("subchangeusername",newValue);
                },
                data_subage(newValue){
      
      
                    // 发生了修改,发送事件
                    this.$emit("subchangeage",newValue);
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
                username: 'HelloWorld',
                age: 12
            },
            methods: {
      
      
                fatherChangeUsername(value){
      
      
                    this.username = value;
                },
                fatherChangeAge(value){
      
      
                    this.age = parseInt(value);
                }
            }
        });
    </script>
</body>

Nine, the parent component directly accesses the child component

How to use: $childrenor$refs

9.1. Method 1: $children

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component></my-component>
        <input type="button" value="单击" @click="handleClick">
    </div>

    <template id="myTemplate">
        <div>
            这个是子组件
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function(){
      
      
                return {
      
      
                    username: "HelloWorld"
                }
            },
            methods: {
      
      
                info(){
      
      
                    console.info("子组件的用户名:" + this.username);
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            methods: {
      
      
                handleClick(){
      
      
                    // 单击父组件的按钮,执行该函数,目的是访问子组件中的数据和调用子组件中的方法
                    console.info(this.$children); // 返回的结果是一个数组
                    for (let comp of this.$children){
      
      
                        console.info(comp.username);
                        comp.info();
                    }
                }
            }
        });
    </script>
</body>

Summary: This method is not used much, and it is very inconvenient to obtain specific subcomponents by subscripting.

9.2. Method 2: $refs

<body>
    <div id="myDiv">
        <my-component ref="comp1"></my-component>
        <my-component ref="comp2"></my-component>
        <input type="button" value="单击" @click="handleClick">
    </div>

    <template id="myTemplate">
        <div>
            这个是子组件
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function(){
      
      
                return {
      
      
                    username: "HelloWorld"
                }
            },
            methods: {
      
      
                info(){
      
      
                    console.info("子组件的用户名:" + this.username);
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            methods: {
      
      
                handleClick(){
      
      
                    // 单击父组件的按钮,执行该函数,目的是访问子组件中的数据和调用子组件中的方法
                    console.log(this.$refs.comp1.username);
                    this.$refs.comp1.info();

                    console.log(this.$refs.comp2.username);
                    this.$refs.comp2.info();
                }
            }
        });
    </script>
</body>

Summary: This method is similar to giving a component an id value, and directly obtaining a certain component through the id method. Typically, $refsdom elements are fetched by coming and going.

<body>
    <div id="myDiv">
        <p ref="p1">HelloWorld</p>
        <p ref="p2">Spring</p>
        <input type="button" value="操作Dom元素" @click="handleClick">
    </div>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        const app = new Vue({
      
      
            el: "#myDiv",
            methods: {
      
      
                handleClick(){
      
      
                    console.log(this.$refs.p1.innerText);
                    console.log(this.$refs.p2.innerText);
                }
            }
        });
    </script>
</body>

Ten, child components directly access parent components and root components

How to access the parent component:$parent

How to access the root component: $root, that is, the root component of the accessed Vue instance

<body>
    <div id="myDiv">
        <my-component></my-component>
    </div>

    <template id="myTemplate">
        <div>
            这个是子组件
            <input type="button" value="访问父组件" @click="subHandleClick">
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            methods: {
      
      
                subHandleClick(){
      
      
                    // 访问父组件
                    console.log(this.$parent.message);
                    this.$parent.fatherInfo();

                    // 访问根组件
                    console.log(this.$root.message);
                    this.$root.fatherInfo();
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data: {
      
      
              message: 'Spring'
            },
            methods: {
      
      
                fatherInfo(){
      
      
                    console.info("父组件的信息:" + this.message);
                }
            }
        });
    </script>
</body>

11. Slots

11.1. Description

​ The slot is actually equivalent toPlaceholder. It takes a place in the component for your HTML template and lets you pass in some stuff. It is decided to insert the carried content into a specified position, so that the template is divided into blocks, with modular characteristics and greater reusability.

Whether the slot is displayed or not and how to display it is controlled by the parent component, while where the slot is displayed is controlled by the child component.

Applicable scenarios: those that can treat multiple components as a whole, and this whole will be reused. But some parts of it are not fixed.

11.2. Case of HelloWorld

Requirements: I now have a div, which is a sub-component, which contains common code, which is the p tag, but the effect of this sub-component on different pages is still slightly different. Maybe page A is a button button, and page B page may be a p tag.

11.2.1 Simple case

<body>
    <div id="myDiv">
        <my-component>
            <button>这个是按钮</button>
        </my-component>
        -------------------------------------- <br>
        <my-component>
            <p>这个是p标签</p>
        </my-component>
    </div>

    <template id="myTemplate">
        <div>
            <p>我是子组件</p>
            <slot></slot>		// 相当于是占位符
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
        });
        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

11.2.2. Improvement: Specify default content for slots

<body>
    <div id="myDiv">
        <my-component>			
        </my-component>
        -------------------------------------- <br>
        <my-component>
            <p>这个是p标签</p>
        </my-component>
    </div>

    <template id="myTemplate">
        <div>
            <p>我是子组件</p>
            <slot>
                <button>这个是按钮,为插槽指定默认内容</button>
            </slot>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
        });
        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

Summary: In this case, slota button is set in the slot button, which is equivalent to a default value. At this time, when using this component, it is not necessary to pass it in, so the default value is used. buttonIf it is passed in, then it is Use the specified incoming DOM template.

11.3. Named slots

​ Explanation: If there are multiple slots in a component, how to fill the specified slot with content. At this time, it is necessary to provide a name for each slot. This slot is called a named slot.

11.3.1, problem case

<body>
    <div id="myDiv">
        <my-component>
            <button>此处替换为按钮</button>
          	<p>此处是P标签</p>
        </my-component>
    </div>
    <template id="myTemplate">
        <div>
            <slot><p>Tomcat</p></slot>
            <p>我是子组件</p>
            <slot><p>HelloWorld</p></slot>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
        });
        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

slotSummary: You will find that the contents of the slots in the component are replaced by buttonand .p

11.3.2. Solution 1

<body>
    <div id="myDiv">
        <my-component>
            <button slot="slot1">此处替换为按钮</button>
            <p>此处是P标签</p>
        </my-component>
    </div>

    <template id="myTemplate">
        <div>
            <slot name="slot1"><p>Tomcat</p></slot>
            <p>我是子组件</p>
            <slot name="slot2"><p>HelloWorld</p></slot>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
        });

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

11.3.3. Solution 2

<body>
    <div id="myDiv">
        <my-component>
            <template v-slot:slot1>
                <button>此处替换为按钮</button>
            </template>
            <p>此处是P标签</p>
        </my-component>
    </div>

    <template id="myTemplate">
        <div>
            <slot name="slot1"><p>Tomcat</p></slot>
            <p>我是子组件</p>
            <slot name="slot2"><p>HelloWorld</p></slot>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
        });

        const app = new Vue({
      
      
            el: "#myDiv"

        });
    </script>
</body>

Note: When using slots, the single use of slots has been discarded in Vue2.6 version, replaced by v-slot.

11.4. Compilation scope

11.4.1, Case 1

<body>
    <div id="myDiv">
        <my-component v-show="isShow"></my-component>
    </div>

    <template id="myTemplate">
        <div>
           <p>我是HelloWorld</p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function () {
      
      
                return {
      
      
                    isShow: true
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data:{
      
      
                isShow: false
            }
        });
    </script>
</body>

Look at the code: there is an isShow in the data attribute of the Vue instance, the value is false, and there is also an isShow attribute in the subcomponent, the value is true. When using the subcomponent, the isShow in the Vue instance is actually my-component v-show="isShow"used isShow, so subcomponents are not displayed on the page.

Note: Through this case, it is found that when using the isShow variable, the operation is as follows: it depends on which template/component the isShow variable is in, not which sub-component the variable is used by. Taking the current case as an example, the variable isShow is in a myDivtemplate called this, so the scope of the variable isShow is the Vue instance, so of course the data in the Vue instance is used.

11.4.2, Case 2

<body>
    <div id="myDiv">
        <my-component v-show="isShow"></my-component>
    </div>

    <template id="myTemplate">
        <div>
           <p v-show="isShow">我是HelloWorld</p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function () {
      
      
                return {
      
      
                    isShow: false
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv",
            data:{
      
      
                isShow: true
            }
        });
    </script>
</body>

Case: Change the value of isShow in the data of the Vue instance to true, change the value of isShow in the subcomponent to false, and templateuse isShow in the template/subcomponent, you will find that the page still does not display the content of the subcomponent , at this time, the isShow in the template uses the isShow in the subcomponent.

11.5. Scoped slots

11.5.1. Description

Meaning: The parent component replaces the slot's label, but the content is provided by the child component.

11.5.2. Case

​ Requirements: A subcomponent has a set of data, such as an array, then these data need to be displayed on multiple interfaces, some interfaces may need to be arranged horizontally, some interfaces may need to be arranged vertically, and some interfaces may directly display an array. The problem is: the data is in the child component, expect the parent component

Tell us how to show, how to do it? At this point, you need to use == slot scope slot ==.

11.5.2.1. Method 1

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component>
            <div slot-scope="subData">
                {
   
   { subData.data.join(' - ') }}
            </div>
        </my-component>
        <my-component>
            <template slot-scope="subData">
                {
   
   { subData.data.join(' * ') }}
            </template>
        </my-component>
    </div>

    <template id="myTemplate">
        <div>
           <slot :data="addresses">
               <ul>
                   <li v-for="item in addresses">
                       {
   
   { item }}
                   </li>
               </ul>
           </slot>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function () {
      
      
                return {
      
      
                    addresses: ['河南林州',"浙江杭州","陕西西安"]
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

11.5.2.2, Method 2

​ Updated since 2.6.0. For obsolete uses slot-scope, use v-slotinstead, written directly on the component label.

<body>
    <div id="myDiv">
        <my-component></my-component>
        <my-component v-slot="subData">
            {
   
   { subData.data.join(' - ') }}
        </my-component>
        <my-component  v-slot="subData">
            {
   
   { subData.data.join(' * ') }}
        </my-component>
    </div>

    <template id="myTemplate">
        <div>
           <slot :data="addresses">
               <ul>
                   <li v-for="item in addresses">
                       {
   
   { item }}
                   </li>
               </ul>
           </slot>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script type="text/javascript">

        Vue.component("myComponent",{
      
      
            template: "#myTemplate",
            data: function () {
      
      
                return {
      
      
                    addresses: ['河南林州',"浙江杭州","陕西西安", "云南大理"]
                }
            }
        });

        const app = new Vue({
      
      
            el: "#myDiv"
        });
    </script>
</body>

Guess you like

Origin blog.csdn.net/qq_48652579/article/details/132040930