Vue.js组件化开发

组件化开发

基本概念

vue.js 有两大法宝,一个是数据驱动,另一个就是组件化

什么叫组件化

所谓组件化,就是把页面拆分成多个组件,每个组件依赖的 CSS、JS、模板、图片等资源放在一起开发和维护
因为组件是资源独立的,所以组件在系统内部可复用,组件和组件之间可以嵌套,如果项目比较复杂,可以极大简化代码量,并且对后期的需求变更和维护也更加友好。

组件化思想

1.如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展.
2.但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了.
参考:组件基础

认识组件

根组件

被挂载管理的元素块就是一个根组件。在此根组件中可以嵌套多个子组件,根组件一般来说只需要一个

<body>
  <div id='app'>
  </div>

  <script src="vue.js"></script>
  <script>
    const app = new Vue({
      el:'#app',
    })
  </script>
</body>

子组件

子组件即是被嵌套在根组件中的组件,子组件可复用,并且数据都是相互独立的。
子组件拥有根组件所拥有的所有属性

组件声明

组件的使用分三个步骤:

1.创建组件构造器
2.注册组件
3.使用组件
1.调用Vue.extend()方法创建组件构造器
2.调用Vue.component()方法注册组件
3.在Vue实例的作用范围内使用组件

全局组件

全局组件会自动进行注册,任何Vue的实例都能进行使用。
使用Vue.component("name",{})对其进行声明并注册。

<body>
    <div id='app'>
        <!-- 3.使用组件  -->
        <cpn></cpn>

    </div>

    <script src="vue.js"></script>
    
    <script>
        // 1.创建组件构造器对象
        const cpnC = Vue.extend({
            template: `
            <div>
                <h2>第一个组件</h2>
            </div>`
        })
        // 2.注册组件 (全局组件)
        Vue.component('cpn',cpnC);

        const app = new Vue({
            el:'#app',
        })
    </script>
</body>

局部组件

局部组件在Vue实例下使用components进行注册,它只能在当前实例使用

<body>
    <div id='app'>
        <!-- 3.使用组件  -->
        <cpn></cpn>
    </div>

    <script src="vue.js"></script>
    
    <script>
	// 1.创建组件构造器对象
        const cpnC = Vue.extend({
            template:`
            <div>
                <h2>第一个组件</h2>
            </div>`
        })

        const app = new Vue({
            el:'#app',
            // 2.注册组件(局部组件)
            components: {
                cpn:cpnC,
            }
        })
    </script>
</body>

组件语法糖写法

这种写法居多

<body>
    <div id='app'>
        <cpn1></cpn1>
        <cpn2></cpn2>
    </div>

    <script src="vue.js"></script>
    
    <script>
        // 全局语法糖
        Vue.component('cpn2',{
            template:`
                <div>
                    <h1>第一个组件</h1>
                </div>`
        })

        const app = new Vue({
            el:'#app',
            components: {
                // 局部语法糖
                cpn1: {
                    template: `
                        <div>
                            <h1>第一个组件</h1>
                        </div>
                    `
                }
            }
        })
    </script>
</body>

组件模板抽离写法

如果在定义组件时在template属性中写HTML代码,是不太友好的,你可以将模板抽离出来。
而且这个方法是用的最多
使用<template>标签配合id属性将其作为子组件模板:(以下抽离包括全局和局部)

<body>
    <div id='app'>
        <cpn1></cpn1>
        <cpn2></cpn2>
    </div>

    <template id='cpn1'>
        <div>
            <h1>组件抽离</h1>
        </div>
    </template>

    <template id='cpn2'>
        <div>
            <h1>组件抽离</h1>
        </div>
    </template>
    <script src="vue.js"></script>
    
    <script>
        // 全局抽离写法
        Vue.component('cpn1', {
            template:'#cpn1'
        })


        const app = new Vue({
            el:'#app',
            // 局部抽离写法
            components: {
                cpn2: {
                    template:'#cpn2',
                }
            }
        })
    </script>
</body>

子组件中的data

上面已经说过,子组件可以拥有data/methods/computed/watch/filter等对象。
但是需要注意的是子组件的data必须是一个函数,且必须返回一个Object
这是因为每个子组件是相互独立的,每一个组件实例都有属于组件的状态
如果组件中的data是一个对象,那么组件进行多次调用的时候就会互相影响。
所以子组件中的data必须是一个函数,因为函数调用时会重新申请内存,返回一个全新的Object

<body>
    <div id='app'>
        <cpn1></cpn1>
        <cpn2></cpn2>
    </div>

    <template id='cpn1'>
        <div>
            <h1>{{title}}</h1>
            <p>{{content}}</p>
        </div>
    </template>
		
    <template id='cpn2'>
        <div>
            <h1>{{title}}</h1>
            <p>{{content}}</p>
        </div>
    </template>
		
    <script src="vue.js"></script>
    
    <script>
	// 全局注册的组件
        Vue.component('cpn1', {
            template:'#cpn1',
	    // data必须是函数
            data() {
                return {
                    title:'我是标题11',
                    content:'我是内容11',
                }
            }
        })

        const app = new Vue({
            el: '#app',
	    // 局部注册的组件
            components: {
                cpn2: {
                    template: '#cpn2',
		    // data必须是函数
                    data() {
                        return {
                            title: '我是标题22',
                            content: '我是内容22',
                        }
                    }
                }
            }
        })
    </script>
</body>

组件通信

通信的意义

组件之间的通信是十分有必要的,当Vue项目启动后,父组件获取到了一些数据,它将如何把这些数据分发到子组件上。
再比如,子组件上产生了一个新数据,它将如何把该数据交由父组件?

父传子(props)

父组件向子组件传递数据时,则通过props进行传递。
接收值在父组件模板中采用 - 分割命名,在props中采用驼峰式,在子组件模板中进行使用时采用与props中同样的命名方式
这是因为 - 分割命名方式不是Js的合法变量名,如果props中采用 - 来进行命名,子组件模板在使用时将查询不到该变量名
总结一句话:如果props中采用了驼峰标识(例如:cInfo),那么在父组件中使用必须用 - 来分割(例如:c-info

<body>
    <!-- 父组件模板 -->
    <div id='app'>
	<!-- 定义接收:一定要使用 - 来分割,不能使用驼峰标识 -->
        <cpn :c-message='message' :c-moves='moves' :c-info='info'></cpn>
    </div>


    <!-- 子组件模板 -->
    <template id='cpn'>
	<!-- 在子组件中就能使用 props 中接收的变量来渲染 -->
        <div>
            <h1>{{cMessage}}</h1>
            <ul>
                <li v-for='item in cMoves'>{{item}}</li>
            </ul>
            {{cMoves}}

            <h2>{{cInfo.name}}</h2>
        </div>
    </template>

    <script src="vue.js"></script>

    <script>
        // 父组件
        const app = new Vue({
            el: '#app',
            data: {
                message: '父组件的message',
                moves:['父组件1','父组件2','父组件3'],
                info: {
                    name:'hollow',
                    age:18,
                    height:1.88,
                }
            },
						
            components: {
                // 子组件
                cpn: {
                    template: '#cpn',
		    // 使用props来接收父组件传过来的三个变量
                    props: {
		    // 接受收的时候可以随便取名
                        cMessage: {
                            type:String,
                            default:'null',
                            required:true,
                        },
                        cMoves: {
                            type:Array,
                            default:[],
                        },
                        cInfo: {
                            type:Object,
                            default:{},
                        }
                    }
                }
            }
        })
    </script>
</body>

props中的其他参数

在上述中我在props中添加了其他参数

描述
type String、Array、Object等 定义接收的数据类型
default 默认值 如果定义了default,那么接收到的就是默认值
required true/false 定义是否必须接收参数,不写默认false

子传父($emit)

1.在子组件中创建自定义函数
2.在自定义函数使用$emit,把需要修改或者传递的值或方法给父组件
3.父组件接收子组件传递过来的自定义函数
4.父组件通过接收的值或方法来进行下一步操作

<body>
    <div id='app'>
	<!-- 3.父组件接收子组件传递过来的自定义函数 -->
        <cpn @item-click='cpnClick'></cpn>
    </div>

    <template id='cpn'>
        <div>
	    <!-- 1.在子组件中创建自定义函数 -->
            <button v-for='item in categories' @click='btnClick(item)'>{{item.name}}</button>
        </div>
    </template>
    <script src="vue.js"></script>
    
    <script>
        const app = new Vue({
            el:'#app',
            components: {
                cpn: {
                    template:'#cpn',
                    data() {
                        return {
                            categories:[
                                {id:'aaa',name:'热门推荐'},
                                {id:'bbb',name:'事件数码'},
                                {id:'ccc',name:'家用家电'},
                                {id:'ddd',name:'电脑办公'},
                            ]
                         }
                     },
                    methods: {
                        // 2.自定义函数:使用$emit,把需要修改或者传递的值或方法给父组件
                        btnClick(item) {
                            this.$emit('item-click',item);
                        }
                    }
                },
            },

	    // 4.父组件通过接收的值或方法来进行下一步操作
            methods: {
                cpnClick(item) {
                    console.log('cpnclick',item);
                }
            }
        })
    </script>
</body>

组件访问

父访问子($children)

有的时候我们想直接通过父组件拿到子组件这个对象,调用其下面的某一个方法,可以使用$children属性完成操作。

<body>
    <div id='app'>
        <cpn></cpn>
        <button @click='btnClick'>app按钮</button>
    </div>


    <template id='cpn'>
        <div>
            <h1>我是子组件</h1>
        </div>
    </template>
    <script src="vue.js"></script>

    <script>
        const app = new Vue({
            el: '#app',
            methods: {
                btnClick() {
		    // 使用$children获取子组件的内容进行操作
                    console.log(this.$children);
                    this.$children[0].show();
                    console.log(this.$children[0].name);
                }
            },
            components: {
                cpn: {
                    template:'#cpn',
                    methods: {
                        show() {
                            console.log('showMessage');
                        }
                    },
                    data() {
                        return {
                            name:'我是子组件',
                        }
                    },
                }
            }
        })
    </script>
</body>

父访问子(refs)

上述的访问方法并不常用,因为父组件非常依赖索引值来访问子组件。
使用$refs来访问子组件就方便的多,我们需要给子组件取一个名字,再用父组件进行调用,这个是非常常用的手段。

<body>
    <div id='app'>
	<!-- 设置ref属性 -->
        <cpn ref="ref1"></cpn>
        <button @click='btnClick'>app按钮</button>
    </div>


    <template id='cpn'>
        <div>
            <h1>我是子组件</h1>
        </div>
    </template>
    <script src="vue.js"></script>

    <script>

        const app = new Vue({
            el: '#app',
            data: {

            },
            methods: {
                btnClick() {
		    // 通过 $refs 来获取子组件的内容进行操作
                    this.$refs.ref1.show();
                    console.log(this.$refs.ref1.name);
                }
            },
            components: {
                cpn: {
                    template:'#cpn',
                    methods: {
                        show() {
                            console.log('showMessage');
                        }
                    },
                    data() {
                        return {
                            name:'我是子组件',
                        }
                    },
                }
            }
        })
    </script>
</body>

子访问父(\(parent)和\)(root)

如果在子组件中想拿到父组件的对象,使用$parent即可,如果存在多层嵌套,它只会拿自己上一层。
如果存在三级或以上嵌套,可以直接使用$root来访问根组件。与$parent使用相同,但是它是具体的一个对象,而并非Array。
下面代码我一起演示了$parent$root

<body>
    <!-- 根组件 -->
    <div id='app'>
        <cpn></cpn>
    </div>

    <!-- 子组件 -->
    <template id='cpn'>
	<!-- 子组件里挂载子子组件 -->
        <ccpn></ccpn>
    </template>

    <!-- 子子组件 -->
    <template id='ccpn'>
        <div>
            <h2>我是子子组件</h2>
            <button @click='btnClick'>按钮</button>
        </div>
    </template>
    <script src="vue.js"></script>
    
    <script>
        const app = new Vue({
	    // 根组件
            el: '#app',
            data: {
                message:'你好啊',
                name:'我是根的name',
            },
            components: {
		// 子组件
                cpn: {
                    template:'#cpn',
                    data() {
                        return {
                            name:'我是cpn的name',
                        }
                    },
		    // 子组件里注册组件,也就是子子组件
                    components: {
                        ccpn: {
                            template:'#ccpn',
                            methods: {
                                btnClick() {
                                    // 通过this.$parent和this.$root访问父组件,也可以通过.的方式获取变量和方法
                                    console.log('父组件是:',this.$parent);
                                    console.log(this.$parent.name);
                                    console.log('根组件是',this.$root);
                                    console.log(this.$root.name);
                                }
                            },
                        }
                    }
                }
            }
        })
    </script>
</body>

下一篇 webpack前端模块化打包工具

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

上一篇:Vue.js基础
下一篇:webpack前端模块化打包工具

posted @ 2020-11-21 12:59  hollows  阅读(488)  评论(0)    收藏  举报
当前浏览器不支持canvas,请更换浏览器后再试