Vue组件化开发入门

目录

1、组件化思想

2、组件的使用

3、全部组件和局部组件

4、父组件和子组件的区分

5、注册组件的语法糖

6、组件模板抽离

7、组件的数据域data必须是函数

8、父子组件通信 - 父传子prop

9、父子组件通信 - 子传父(自定义事件)

10、父子组件通信 - 双向绑定

11、父子组件的访问方式

(1)父访问子  $children或$refs

(2)子访问父$parent

(3)访问Vue实例$root

12、slot插槽的基本使用

13、slot具名插槽的使用

14、作用域插槽


 

1、组件化思想

组件化是Vue.js中的重要思想。

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

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

2、组件的使用

  1. 创建组件构造器:Vue.extend()
  2. 注册组件:Vue.component();
  3. 使用组件
<div id="demo">
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
</div>
<script>
    //创建组件构造器对象
    const cpnConstructor = Vue.extend({
        template: `<div>
    <h2>我是标题</h2>
    <p>我是内容</p>
    <p>我是内容哈哈哈哈哈哈哈</p>
</div>`,
    });
    //注册组件
    //component(组件标签名,组件构造器)
    Vue.component('my-cpn',cpnConstructor)

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

 

3、全部组件和局部组件

全局组件的注册

//注册全局组件:全局组件意味着可以在多个vue实例对象下使用
Vue.component('my-cpn', cpnConstructor)

局部组件的注册

const app = new Vue({
    el: '#demo',
    components:{
        //组件标签名:组件构造器
        cpn:cpnConstructor
    }
});

4、父组件和子组件的区分

<div id="demo">
    <cpn2></cpn2>
</div>
<script>
    //创建第一个组件构造器
    const cpn1 = Vue.extend({
        template: `
        <div>
            <h2>我是标题1</h2>
            <p>我是内容哈哈哈哈哈1</p>
            <p>我是内容哈哈哈哈哈1</p>
            <hr>
        </div>
        `,
    });
    //创建第二个组件构造器
    const cpn2 = Vue.extend({
        template: `
        <div>
            <h2>我是标题2</h2>
            <p>我是内容哈哈哈哈哈2</p>
            <p>我是内容哈哈哈哈哈2</p>
            <hr>
			<cpn1></cpn1>
        </div>
        `,
        components:{
            cpn1: cpn1,
        }
    });
    const app = new Vue({
        el: '#demo',
        components:{
            cpn2:cpn2,
        },
    });
</script>

cpn2就是父组件,cpn1就是子组件

 

5、注册组件的语法糖

<div id="demo">
    <cpt></cpt>
    <hr>
    <cpt2></cpt2>
</div>
<script>
    //注册全局组件
    Vue.component('cpt', {
        template: `
            <div>
                <h2>我是标题111</h2>
                <p>语法糖语法糖语法糖111</p>
            </div>
            `,
    });

    let vm = new Vue({
        el: '#demo',
        //注册局部组件语法糖
        components: {
            cpt2: {
                template: `
                <div>
                    <h2>我是标题222</h2>
                    <p>语法糖语法糖语法糖222</p>
                </div>
                `,
            }
        },
    });
</script>

 

6、组件模板抽离

使用<script id="cpt" type="text/x-template">标签

<div id="demo">
    <cpt></cpt>
    <cpt></cpt>
    <cpt></cpt>
</div>
<script id="cpt" type="text/x-template">
    <div>
        <h2>我是标题</h2>
        <p>我是内容哈哈哈哈哈</p>
        <p>我是内容哈哈哈哈哈</p>
        <hr>
    </div>
</script>
<script>
    let vm = new Vue({
        el: '#demo',
        components: {
            cpt: {
                template: '#cpt',
            }
        }
    });
</script>

或者使用template标签

<template id="cpt2">
    <div>
        <h2>我是标题222</h2>
        <p>我是内容哈哈哈哈哈222</p>
        <p>我是内容哈哈哈哈哈222</p>
        <hr>
    </div>
</template>

 

7、组件的数据域data必须是函数

注意:组件不可以直接访问Vue实例里的数据!Vue组件有自己保持数据的地方。

<script id="cpt" type="text/x-template">
    <div>
        <h2>{{ title }}</h2>
        <p>我是内容哈哈哈哈哈</p>
        <p>我是内容哈哈哈哈哈</p>
        <hr>
    </div>
</script>
<script>
    let vm = new Vue({
        el: '#demo',
        components: {
            cpt: {
                template: '#cpt',
                data() {
                    return {
                        title:'ABC',
                    }
                },
            },
        },
    });
</script>

 

组件里的data必须是一个函数,要返回一个实例对象,我们可以在这个对象里存放数据。

 

8、父子组件通信 - 父传子props

props传值有两种方式

  • 方式一:字符串数组,数组中的字符串是传递时的名称
  • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值
<template id="fu">
    <div>
        <h2>父组件</h2>
        <hr>
        <zi v-bind:moviezi="movies" :messagezi="message"></zi>
    </div>
</template>
<template id="zi">
    <div>
        <h2>子组件</h2>
        <h2>{{ messagezi }}</h2>
        <h2>{{ moviezi }}</h2>
        <hr>
    </div>
</template>
<div id="demo">
    <fu></fu>
</div>
<script>
    Vue.component('zi', {
        template: '#zi',
        props: ['moviezi', 'messagezi'],
    });

    let vm = new Vue({
        el: '#demo',
        components: {
            fu: {
                template: '#fu',
                data() {
                    return {
                        movies: ['123', 456, '789'],
                        message: '没错我是子组件要用的消息',
                    }
                },
            },
        }

    });
</script>

在子组件中定义props,在父组件使用子组件时,用v-bind让子组件的props和父组件的data绑定关系

也可以使用对象传递,

这个时候我们可以指定类型验证

        props: {
            /*可指定类型*/
            moviezi: Array,
            messagezi: String,
        }

支持验证的数据类型有:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
  • 当我们有自定义构造函数时,也可以支持自定义类型的验证

还可以指定默认值,在没有传值的情况下生效。

        props: {
            /*可指定类型*/
            /*可提供默认值*/
            moviezi: {
                type:Array,
                default:[1,2,3,4,5,6]
            },
           messagezi: {
                type:String,
                default: 'defaultValue',
                //required:为true时,指定这个值必须传递(绑定),不传就报错
                required:true,
            },
        }

 

注意:props中的驼峰标识aaBbCc,使用时要转换为aa-bb-cc

比如props定义的seeMovies,在v-bind绑定和使用时,要这样用:see-movies

 

9、父子组件通信 - 子传父(自定义事件)

<template id="zi">
    <div>
        <h2>zi组件</h2>
        <h2>{{ message }}</h2>
        <button v-for="item in certificates"
                @click="btnclick(item)"
                :key="item.id">{{ item.name }}
        </button>
        <hr>
    </div>
</template>
<template id="fu">
    <div>
        <h2>fu组件:</h2>
        <h2>{{ fumessage }}</h2>
        <h2 id="fumessage"></h2>
        <hr>
        <zi @itemclick="fuhanadler"></zi>
    </div>
</template>
<div id="demo">
    <fu></fu>
</div>
<script>
    const zi = Vue.component('zi', {
        template: '#zi',
        data() {
            return {
                message: '子组件的message',
                certificates: [
                    {
                        id: 1,
                        name: 'type1'
                    },
                    {
                        id: 2,
                        name: 'type2'
                    },
                    {
                        id: 3,
                        name: 'type3'
                    },
                    {
                        id: 4,
                        name: 'type4'
                    },
                ]
            }
        },
        methods: {
            btnclick(item) {
                //子组件发射事件(自定义事件,传递的参数)
                this.$emit('itemclick',item);
            }
        }
    });
    Vue.component('fu', {
        template: '#fu',
        components: {
            zi: zi
        },
        data() {
            return {
                fumessage: 0,
            }
        },
        methods: {
            fuhanadler(item) {
                this.fumessage = item.id;
            }
        }

    });
    let vm = new Vue({
        el: '#demo',
        data: {
            message: '',
        }

    });
</script>

1、子组件的methods中定义自定义事件,使用this.$emit将事件传递出去

2、父组件在使用子组件时,注册已经定义的自定义事件

3、父组件中定义事件绑定的方法

 

10、父子组件通信 - 双向绑定

尝试实现但不推荐

<template id="zi">
    <div>
        <h2>zi组件:</h2>
        <h2>number1:{{ number1 }}</h2>
        <h2>number2:{{ number2 }}</h2>
        <label>number1:
            <input type="text" v-model="number1">
        </label>
        <br>
        <label>number2:
            <input type="text" v-model="number2">
        </label>
    </div>
</template>
<template id="fu">
    <div>
        <h2>fu组件</h2>
        <h2>num1:{{ num1 }}</h2>
        <h2>num2:{{ num2 }}</h2>
        <label>num1:
            <input type="text" v-model="num1">
        </label>
        <label>num2:
            <input type="text" v-model="num2">
        </label>
        <hr>
        <zi :number1="num1" :number2="num2"></zi>
    </div>
</template>
<div id="demo">
    <fu></fu>
</div>
<script>
    const zi = Vue.component('zi', {
        template: '#zi',
        props: {
            number1: Number,
            number2: Number,
        }
    });
    let vm = new Vue({
        el: '#demo',
        data: {
            message: '',
        },
        components: {
            fu: {
                template: '#fu',
                components: {
                    zi: zi,
                },
                data() {
                    return {
                        num1: 1,
                        num2: 2,
                    }
                },
            }
        }
    });
</script>

测试发现,父组件的属性,通过v-model的绑定,修改可以同步子组件的数据,而子组件通过v-model绑定进行进行修改,则不可以影响到父组件的数据。

而且有报错。

子组件通过v-model绑定进行进行修改,不可以影响到父组件的数据
父组件的属性的修改,可以同步子组件的数据

改进:

<template id="zi">
    <div>
        <h2>zi组件:</h2>
        <h2>props:number1:{{ number1 }}</h2>
        <h2>props:number2:{{ number2 }}</h2>
        <h2>data:dnumber1:{{ dnumber1 }}</h2>
        <h2>data:dnumber2:{{ dnumber2 }}</h2>
        <label>number1:
            <input type="text"
                   v-model="dnumber1"
                   @input="number1Input">
        </label>
        <br>
        <label>number2:
            <input type="text" v-model="dnumber2">
        </label>
    </div>
</template>
<template id="fu">
    <div>
        <h2>fu组件</h2>
        <h2>num1:{{ num1 }}</h2>
        <h2>num2:{{ num2 }}</h2>
        <label>num1:
            <input type="text" v-model="num1">
        </label>
        <br>
        <label>num2:
            <input type="text" v-model="num2">
        </label>
        <hr>
        <zi :number1="num1"
            :number2="num2"
            @number1input="changenum1"></zi>
    </div>
</template>
<div id="demo">
    <fu></fu>
</div>
<script>
    const zi = Vue.component('zi', {
        template: '#zi',
        props: {
            number1: String,
            number2: String,
        },
        data() {
            return {
                dnumber1:this.number1,
                dnumber2:this.number1,
            }
        },
        methods:{
            number1Input(event){
                this.dnumber1 = event.target.value;
                this.$emit('number1input',this.dnumber1);
            }
        }
    });
    let vm = new Vue({
        el: '#demo',
        data: {
            message: '',
        },
        components: {
            fu: {
                template: '#fu',
                components: {
                    zi: zi,
                },
                data() {
                    return {
                        num1: '1',
                        num2: '2',
                    }
                },
                methods:{
                    changenum1(number1){
                        this.num1 = number1;
                    }
                }
            }
        }
    });
</script>

思路:使用data替代props和input进行绑定,子组件的input双向绑定了data的dnumber1,这时,data:dnumber会随着输入变,

同时,子组件绑定input事件,在触发的方法中,向父组件发射自定义事件,把修改的值传递过去,

父组件使用子组件时,注册自定义事件,并绑定触发方法,方法内实现修改父组件的对应数据。

父组件的方法修改了对应数据后,由于props的缘故,父组件又把修改后的数据传递到子组件的props的number1,所以number1也改变了,

相当于三向绑定,C绑定A,A指定B,B绑定C.....当B修改时,并不会马上修改A,但会修改C,而C又可以修改A,所以A也随之改变,有点绕。

 

11、父子组件的访问方式

(1)父访问子  $children或$refs

this.$children是一个数组类型,它包含所有子组件的对象。,我们可以通过讴歌遍历,取出所有子组件的message状态。

<template id="cpn">
    <div>
        <h2>cpn</h2>
        <button @click="showMessage">Click</button>
    </div>
</template>
<div id="demo">
    <cpn></cpn>
    <cpn></cpn>
    <hr>
    <button @click="btnClick">父组件的click</button>
</div>
<script>
    let vm = new Vue({
        el: '#demo',
        data: {
            messages: '123',
        },
        methods:{
            btnClick(){
                console.log(this.$children);
                //调用子组件的方法
                //this.$children[0].showMessage();
                //使用子组件的属性
                alert(this.$children[0].message+'打印')
            }
        },
        components: {
            cpn: {
                template: '#cpn',
                data() {
                    return {
                        message: 'message#cpn'
                    }
                },
                methods: {
                    showMessage() {
                        alert(this.message)
                    },
                }
            }
        }
    });
</script>
$children拿到子组件的一些东西

 

在使用子组件的时候,用ref属性指定一个xxxid,使用this.$refs.xxxid就可以得到子组件的对象。

(2)子访问父$parent

使用方法和上边一样,但是不推荐使用,耦合性太高了。

(3)访问Vue实例$root

 

12、slot插槽的基本使用

类似于Java里的泛型

<template id="cpn">
    <div>
        <hr>
        <h2>cpn</h2>
        <p>我是cpn组件</p>
        <slot>
            <input type="text" placeholder="插槽的默认值">
        </slot>
        <hr>
    </div>
</template>
<div id="demo">
    <cpn>
        <button>按钮一</button>
    </cpn>
    
    <cpn><h2>标题二</h2></cpn>

    <cpn></cpn>
</div>

在template里定义slot标签,作为插槽。

slot标签内可以定义默认值,没有插入时,使用默认值。

使用时,在组件的注册的标签里填上要插入的东西即可。

13、slot具名插槽的使用

定义多个插槽的使用

<template id="cpn">
    <div>
        <hr>
        <h2>cpn</h2>
        <p>我是cpn组件</p>
        <slot name="left"><span>左边的插槽</span></slot>
        <slot name="center"><span>中间的插槽</span></slot>
        <slot name="right"><span>右边的插槽</span></slot>
        <hr>
    </div>
</template>
<div id="demo">
    <cpn></cpn>

    <cpn>
        <span slot="center">替换后的中间插槽</span>
    </cpn>

    <cpn>
        <button slot="right">右边的按钮</button>
    </cpn>
</div>

 

14、作用域插槽

父组件模板的所有信息,都会在父级作用域内编译,子组件模板的所有东西都会在子级作用域内编译。

作用域插槽:父组件替换插槽的标签,但内容由子组件来提供。

<template id="cpn">
    <div>
        <slot name="test" :data="pLanguages">
            <ul>
                <li v-for="item in pLanguages">{{ item }}</li>
            </ul>
        </slot>
        <hr>
    </div>
</template>
<div id="demo">
    <cpn></cpn>

    <cpn>
        <!-- 获取子组件中的pLanguages-->
        <div slot="test" slot-scope="slot">
            <span v-for="i in slot.data">{{ i }}-</span>
        </div>
    </cpn>
</div>
<script>
    let vm = new Vue({
        el: '#demo',
        data: {
            message: '',
        },
        components: {
            cpn: {
                template: '#cpn',
                data() {
                    return {
                        pLanguages: ['Java', 'JavaScript', 'C++', 'C##', 'Python', 'Go'],
                    }
                },
            },
        }
    });

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值