Vue进阶之组件化开发

一.组件化思想介绍

组件化开发,本质就是将相同功能的模块开发成 一个个可以复用的小组件,然后通过引入各个组件实现一个完整页面的开发,组件化开发就像树结构一样,每一个组件都是树形结构上的一个分支节点

1.1 Vue实例创建组件

在Vue中创建组件构造器有几种实现方式,但是大体思想包含3步,如下:
1.创建组件构造器
2.注册组件
3.在Vue实例对象中使用组件

组件第一种创建使用方法,基于extend方式:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewpot" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vuezujianhua</title>
        <script src='./vue.js'></script>
        <style>

        </style>
    </head>
    <body>
        <div id="shop" v-cloak>
            <!-- vue实例对象中使用全局组件 -->
            <my_content></my_content>
        </div>

        <template id="content">
            <div>
                {{childMovies}}
            </div>
        </template>
        <script>
            // 1. 创建组件构造器
            const content = Vue.extend({
                template:`
                    <div>
                        <h2>这是一个标题</h2>
                        <p>这是一段内容</p>    
                    </div>
                `,
            })
            // 2. 注册组件
            Vue.component('my_content', content)
            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },

            })
        </script>
    </body>
</html>

注意点:通过调用Vue中extend方法首先创建组件构造器,这种实现方法比较底层

实现方式二,直接通过Vue.component()语法糖方式实现

Vue.component('my_content', {
                template:`
                    <div>
                        <h2>这是一个标题1</h2>
                        <p>这是一段内容</p>    
                    </div>
                `,
            })

语法糖实现直接将extend中实现模板的内容放到了component中,其实语法糖底层实现也是调用了extend,但是这样实现更简洁

1.2 全局组件和局部组件

全局组件:全局组件的创建和注册都在与vue实例同一层级的结构中实现
例如:
全局组件

<script>
            // 创建组件构造器, 注册组件,这样是一个全局组件,因为组件创建和注册和new Vue实例化同级
            Vue.component('my_content', {
                template:`
                    <div>
                        <h2>这是一个标题1</h2>
                        <p>这是一段内容</p>    
                    </div>
                `,
            })
            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },

            })
        </script>

上面Vue.component()创建组件和注册组件都是通过Vue对象实现,而且和Vue对象实例化同级

局部组件

<script>
            // 创建组件构造器, 注册组件,这样是一个局部组件,因为组件创建和注册放到了vue实例对象中
            var cpm = {
                template:`
                    <div>
                        <h2>这是一个标题111</h2>
                        <p>这是一段内容</p>    
                    </div>
                `,
            }
            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },
                components:{
                    'my_content': cpm
                }
            })
        </script>

局部组件:因为组件创建和注册放到了vue实例对象中,通过components创建注册

1.3 父子组件

子组件在父组件进行注册和创建,引用也在父组件中,例如:
父子组件

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewpot" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vuezujianhua</title>
        <script src='./vue.js'></script>
        <style>

        </style>
    </head>
    <body>
        <div id="shop" v-cloak>
            <!-- vue实例对象中使用全局组件 -->
            <component1></component1>
            <!-- <component2></component2> 子组件中创建的组件只能在父组件中使用,不能越级 -->
        </div>

        <template id="content">
            <div>
                {{childMovies}}
            </div>
        </template>
        <script>
            // 创建组件构造器, 注册组件,这样是一个局部组件,因为组件创建和注册放到了vue实例对象中

            Vue.component('component1', {
                template:`
                    <div>
                        <h2>这是一个标题111</h2>
                        <p>这是一段内容</p>
                        <component2></component2>  
                    </div>
                `,
                components:{
                    'component2':{
                        template:`
                            <div>
                                <h2>这是一个标题222</h2>
                                <p>这是一段内容222</p>    
                            </div>
                        `,
                    }
                }
            })

            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },
            })
        </script>
    </body>
</html>

component2子组件的实现是在其父组件component1中实现的,而且其使用而在component1的template中,而不能放到vue实例中去使用(其实new Vue实例化可以看成一个根组件root,组件化的思想也是基于vue实例化)

1.4 template模板抽离

上面我们把html模板template的内容都放到了组件里面,然后通过template去渲染模板,这样我们组件中会存放很多html模板,这样代码会很臃肿,所以我们要进行解耦,将template抽离

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewpot" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vuezujianhua</title>
        <script src='./vue.js'></script>
        <style>

        </style>
    </head>
    <body>
        <div id="shop" v-cloak>
            <!-- vue实例对象中使用全局组件 -->
            <component1></component1>
            <!-- <component2></component2> 子组件中创建的组件只能在父组件中使用,不能越级 -->
        </div>

        <template id="content">
            <div>
                <div>
                    <h2>这是一个标题111</h2>
                    <p>这是一段内容</p>
                </div>
            </div>
        </template>
        <script>
            // 创建组件构造器, 注册组件,这样是一个局部组件,因为组件创建和注册放到了vue实例对象中

            Vue.component('component1', {
                template:'#content',
            })

            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },
            })
        </script>
    </body>
</html>

注意点:我们在vue实例对象的模板下面添加了template标签,然后通过id设置模板的唯一名称,在Vue.componen他()创建和注册组件时直接通过id选择器定位template后引入并渲染,这样vue组件中不会存放大量的html内容,代码解耦性好

父子组件中模板抽离

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewpot" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vuezujianhua</title>
        <script src='./vue.js'></script>
        <style>

        </style>
    </head>
    <body>
        <div id="shop" v-cloak>
            <!-- vue实例对象中使用全局组件 -->
            <component1></component1>
            <!-- <component2></component2> 子组件中创建的组件只能在父组件中使用,不能越级 -->
        </div>

        <template id="content1">
            <div>
                <div>
                    <h2>这是一个标题111</h2>
                    <p>这是一段内容</p>
                    <component2></component2>
                </div>
            </div>
        </template>


        <template id="content2">
            <div>
                <div>
                    <h2>这是一个标题222</h2>
                    <p>这是一段内容222</p>
                </div>
            </div>
        </template>
        <script>
            // 创建组件构造器, 注册组件,这样是一个局部组件,因为组件创建和注册放到了vue实例对象中

            Vue.component('component1', {
                template:'#content1',
                components: {
                    'component2': {template: '#content2'}
                }
            })

            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },
            })
        </script>
    </body>
</html>

将父组件component1中的子组件component2的模板都抽离出来,然后通过template进行引用,但是要注意的是component2组件的使用只能在component1中,即子组件只能在父组件中进行使用

1.5 子组件中data存放数据

vue中子组件不能直接访问实例中的数据,需要通过绑定访问,子组件中数据存放在data中,和vue实例结构很相似,但是子组件中data是一个能返回对象的函数,函数有自己的作用予,可以起到数据作用域独立,不会造成数据引用混乱
因为函数在调用是,内存中会有一个栈空间来存在函数对象并设置变量,以及分配内存空间进行存放,这样所以创建的变量都是拥有独立的作用域的

<div id="shop" v-cloak>
             <component1></component11>
        </div>
        
        <template id="content">
            <div>
                <h2>{{ title }}</h2>
                <p>我是内容,哈哈哈哈222</p>
                <p>我是内容,呵呵呵呵2222</p>
            </div>
        </template>
        <script>

            Vue.component('component1',{
                template: '#content',
                data(){
                    return {'title': '我是标题22222'}
                },
                methods:{

                }
            })

            var vm = new Vue({
                el:'#shop',
                data:{
                    msg: "kdf",
                },
                methods:{

                },
            })
        </script>

我们看到当(此时可以把vue实例看组root根组件)子组件的template使用到title变量时通过插值表达式进行数据赋值,title时存放在data函数中,并返回一个包含title属性的对象

二. 父子组件通信

父子组件通信分为两种情况
1.父组件通过props向子组件传递数据
2.子组件通过$emit的事件向父组件传递数据,自定义事件

Vue进阶之组件化开发

2.1 父组件通过props向子组件传递数据

通过v-bind将父组件中的数据绑定到子组件中

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewpot" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vuezujianhua</title>
        <script src='./vue.js'></script>
        <style>

        </style>
    </head>
    <body>
        <div id="shop" v-cloak>
            <!-- vue实例对象中使用全局组件 -->
            <component1></component1>
            <!-- <component2></component2> 子组件中创建的组件只能在父组件中使用,不能越级 -->
        </div>

        <template id="content1">
            <div>
                <div>
                    <h2>{{ title + '在父组件中'}}</h2>
                    <p>这是一段内容</p>
                    <component2 :mytitle='title'></component2>
                </div>
            </div>
        </template>


        <template id="content2">
                <div>
                    <h2>{{ mytitle + '子组件中' }}</h2>
                    <p>这是一段内容222</p>
                </div>
        </template>
        <script>
            // 创建组件构造器, 注册组件,这样是一个局部组件,因为组件创建和注册放到了vue实例对象中

            Vue.component('component1', {
                template:'#content1',
                components: {
                    'component2': {
                        template: '#content2',
                        props:{
                        mytitle:{
                            type: String,
                            default(){
                                return "父组件中没有传递title"
                            },
                            required: false
                    }
                }
                    }
                },
                data(){
                    return {'title': '标题222'}
                },
                
            })

            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{

                },
            })
        </script>
    </body>
</html>
vuezujianhua

在子组件中设置props属性并进行简单校验,然后在组件中绑定父组件的中传递的title值,然后在子组件红进行插值引用

2.2 子组件通过$emit自定义事件向父组件传递数据

子组件中向父组件中传递数据时通过自定义事件实现,事件自定义流程如下:
在子组件中触发子组件methods中方法,然后在methods中使用this.$emit(‘eventname’, para)将事件发射到父组件中,然后在父组件的模板template中使用v-on监听子组件传递的事件,然后触父组件中methods进行相应的请求

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewpot" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>vuezujianhua</title>
        <script src='./vue.js'></script>
        <style>
            ul>li {
                list-style: none;
            }
        </style>
    </head>
    <body>
        <!-- 父组件模板 -->
        <div id="shop" v-cloak>
             <son_component @childbtn='fatherbtn'>
             </son_component>
        </div>

        <!-- 子组件模板 -->
        <template id="content">
            <div>
                <ul v-for="item in goodList">
                    <li><a href="#" @click='childclick(item)'>{{item.name}}</a></li>
                </ul>
            </div>
        </template>
        <script>

            const son_component = {
                template: '#content',
                data: function(){
                    goodLists = [
                        {id: '1', name:'热门推荐'},
                        {id: '2', name:'手机数码'},
                        {id: '3', name:'家用家电'},
                        {id: '4', name:'电脑办公'},
                ]
                    return {'goodList': goodLists}

                },
                methods:{
                    childclick(item){
                        this.$emit('childbtn', item); //向父组件中发射事件并传递参数
                    }
                },
            }

            var vm = new Vue({
                el:'#shop',
                data:{
                    movies: ['海王', '海贼王'],
                },
                methods:{
                    fatherbtn(item){
                        console.log("father", item)
                    }
                },
                components:{
                    son_component
                }

            })
        </script>
    </body>
</html>

注意点:子组件通过自定义事件this.$emit(‘eventname’,para)向父组件中发射事件

上一篇:A Survey on Advancing the DBMS Query Optimizer: Cardinality Estimation, Cost Model, and Plan Enumera


下一篇:SOA 的基本概念及设计原则浅议