Vue学习(十二)-Vue的组件化开发

组件化开发

引子

组件化开发是Vue里卖弄非常重要的一个思想

在这里插入图片描述

  • 我们将一个完整的页面分成很多个组件

  • 每个组件都用于实现页面的一个功能块

  • 而每一个组件又可以进行细分

    Vue.js

    • 提供了一种抽象的,可以让我们开发出一个个可复用的小组件来构造我们的应用

    • 任何的应用都会被抽象成一颗组件树

      在这里插入图片描述

基础

所谓的组件化开发,实际上就是把可复用的代码抽成一个模板,能在多个地方重复利用,就像函数

  1. 定义组件

    const cpn = Vue.extend({    // 1. 创造一个组件
        template: `
                <div>
                <a href="https:">666</a>
                <p>我是p标签</p> 
                </div>`
    })
    
    • Vue.extend() 创建的是一个组件构造器
    • template 代表了我们自定义组件的模板,也就是要显示的HTML代码
    • 这种方法在 Vue2.X 已经看不到了,后面的语法糖写法也是基于这种方法实现的
  2. 注册组件

    // 2.1 注册一个组件,该组件是全局组件,可以在多个Vue实例下使用
    Vue.component('my-pn', cpn)
    
    // 2.2 注册局部组件
    const cpn = Vue.extend({ // 1. 创造一个组件
        template: `
                <div>
                <a href="https:">666</a>
                <p>我是p标签</p> 
                </div>`
    })
    var app = new Vue({
        el: '#app',
        data: {
            message: 0,
        },
        components: {
            // my-pn 使用组件时的标签名
            'my-pn': cpn
        }
    })
    
    • 第一个参数是 组件名,在DOM里面我们的自定义标签名
    • 第二个参数是 组件构造器
  3. 使用组件

    <div id="app">
        <my-pn></my-pn>     <!-- 使用自定义组件 -->
        <my-pn></my-pn>
    </div>
    

    在这里插入图片描述

父组件/子组件
  1. 子组件

    const son = Vue.extend({
        template: `
        <div>
        <a href="https:">我是子组件</a>
        <p>我是p标签</p> 
        </div>`
    })
    
  2. 父组件

    const father = Vue.extend({
        template: `
        <div>
        <a href="https:">我是父组件</a>
        <p>我是p标签</p> 
        <sonCpn></sonCpn>
        </div>`,
        components: {
            'sonCpn': son
        }
    })
    
  3. Root组件

    var app = new Vue({
        el: '#app',
        data: {
            message: 0,
        },
        components: {
            // my-pn 使用组件时的标签名
            'my-cpn': father
        }
    })
    
  4. 使用

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

    在这里插入图片描述

注册组件语法糖
  1. 注册全局组件

    // 直接使用compoment注册,不需要写组件构造器,
    // 源码实际上把{}里面的内容自动帮我们构造了组件构造器,所以我们能使用语法糖的写法
    Vue.component('my-cpn', {
        template: `
            <div>我是一个div标签</div>
            `
    })
    
  2. 注册局部组件

    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        },
        components: {
            'my-cpn': {
                template: `<a href="">我是一个a标签</a>`
            }
        }
    })
    
组件模板抽离

body页面上写,把模板单独抽离出来成为一个标签

  1. 写法一

    把模板单独写到一个 script 标签中,在写组件的时候把 script 标签用选择器选中

    <script type="text/x-template" id="son">
    	<div>
    		<h2>今天天气真好</h2>
    		<p>我是一个p</p>
        </div>
    </script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!'
            },
            components: {
                'my-cpn': {
                    template: '#son'
                }
            }
        })
    </script>
    
  2. 写法二

    写到 template标签 里面

    <div id="app">
        <my-cpn></my-cpn>
    </div>
    
    <template id="son">
        <div>
            <h2>今天天气真好</h2>
            <p>我是一个p</p>
        </div>
    </template>
    
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!'
            },
            components: {
                'my-cpn': {
                    template: '#son'
                }
            }
        })
    </script>
    
组件data参数

我们想要组件里面的模板也能使用 {{}} 这样的语法,我们可以再组件的 data 属性里面写!

组件是可复用的 Vue 实例对象,他能接收的参数也包括 eldatamethodscomputed这样的

  1. 组件的复用
    <div id="app">
        <my-cpn></my-cpn>	
        <my-cpn></my-cpn>
        <my-cpn></my-cpn>
    </div>
    <template id="son">
        <div>
            <button @click="counter++">你已经点了我 {{counter}} 次了</button>
        </div>
    </template>
    <script src="VueJs/vue.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!'
            },
            components: {
                'my-cpn': {				// ① 
                    template: '#son',
                    data: function() {	// ②
                        return {
                            counter: 0
                        }
                    }
                }
            }
        })
    </script>
    

    ①:创建了一个Vue 实例的子组件,这个子组件其实也是一个 Vue 实例

    ②:每一个组件实例在被创建的时候,都会调用 data 这个函数,返回一个独一无二,专门用来储存他自己业务和数据的对象,不会受到其他组件的影响

为什么data要用函数
  • 我们定义组件的 data 的时候,不能返回一个对象,它必须是一个函数
  1. 组件是要能被复用的,每个组件的实例都应该有他自己的数据和业务逻辑

  2. 每个实例都应该可以维护一份被返回对象的独立的拷贝的数据

  3. 如果data不是一个函数,而是一个对象,每次创建组件实例,所有实例引用的数据都会是同一个data

  4. 如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到 其它所有组件实例

    在这里插入图片描述

我们用函数来模拟下这个现象,加深对这个data的理解

  1. 如果所有的实例用的都是一个 data 数据,会变成灾难

    const obj = {
        name: 'xyb',
        age: 20,
        sex: 'M'
    }
    
    function People() {
        return obj
    }
    
    let a = People();
    let b = People();
    let c = People();
    
    a.age = 888
    
    console.log(a);				// 1. 这里三个值的age都会被修改
    console.log(b);				// 2. 非常不方便管理,一个数据变动,全部数据都变动
    console.log(c);				// 3. 三个值执行的都是同一个对象
    
  2. 各自的实例有各自管理的数据,各司其职,互不干扰

    function People() {
        return {
            name: 'xyb',
            age: 20,
            sex: 'M'
        }
    }
    
    let a = People();		// a 会指向 People 函数返回的新对象的内存地址上
    let b = People();		// b 会指向 People 函数返回的新对象的内存地址上
    let c = People();		// c 会指向 People 函数返回的新对象的内存地址上
    
    a.age = 888
    
    console.log(a);				// 1. 这里只有a的值会被修改
    console.log(b);				// 2. 用函数返回一个新对象,就能管理各自的数据
    console.log(c);				// 3. 如果data是一个对象,那么所有组件实例都会指向同一个对象
    
父子组件通信
  • 我们在开发的时候,通常都是在最大的组件,也就是 root (最大的Vue实例) 组件里面请求数据,然后在一个个小组件里面渲染出来,不可能说每一个小组件都各自来一次请求数据,服务器给我们返回的数据肯定是一个层层包裹的大数据,需要我们手动把数据分发给小组件进行渲染
组件通信的方式
  1. 父组件通过 props 向子组件传递数据

  2. 子组件通过 事件 向父组件发送消息

    在这里插入图片描述

    props


    子组件用来接收父组件传入值的重要属性

    // 1. 创建 Vue 实例,创建子组件,把数据在data中定义好
    var app = new Vue({
        el: '#app',
        data: {
            books: ['《星际穿越》', '《弱点》', '《一条狗的使命》'],
            price: [20, 30, 45, 16]
        },
        components: {		// ①
            cpn1: {
                template: `         
                    <div>
                        {{books}}		// 这里的 books 是来自 props 里的
                        {{price}}		// ③
                    </div>`,
                data() {
                    return {
                        counter: 0,
                    } 
                },
                props: ['books', 'price']		// ②
            }
        }
    })
    
    // 2. 重要的部分
    <div id="app"> // :打开了一条通道,能把父(root)组件里的price绑定到子组件上,必须要用props接收
        <cpn1 :books="books" :price="price"> 	// ④
        </cpn1>
    </div>
    

    ①:在root组件上创建一个子组件cpn1

    ②:用来接收父组件绑定到模板上的值。可以是数组/对象

    ③:从组件的 props 里面找数据,找不到报错

    ④::books="books" **: ** 作为一条子组件和父组件的通道,前面一个 books 是子组件 props 里面接收的值

    后面的 books,如果父组件里面的 data 已经定义了,那么就会把定义的数据传入子组件,否者为字符串 books

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值