VUE(五):父子组件通信

  • 父子组件通信指的就是父组件数据需要传递给子组件,那么就需要某种方式传递
  • 父传子通过props属性传递,子传父需要通过自定义事件$emit传递
一、父传子props
1.传递简单数据
  • 如果传递的数据内容比较少或者类型简单,那么可以声明一个prop数组来接收即可
  • 在注册组件时,可以在对象中声明一个props数组来定义子组件变量名,这个变量名不仅是为了区分父组件传来的变量名,而且还是通过v-bind命令绑定父组件数据的重要依据。
  • 注意在用到template模板的地方使用v-bind绑定数据,然后模板内部双花括号取的变量名就是props里声明的值
  • 注意props属性尽量不要使用驼峰命名法,因为不受支持,如果变量真的声明了驼峰命名,那么在v-bind绑定数据的时候要加-,例如cMoives 要写为c-movies
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父组件传子组件</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>

    <template id="tmp">
        <div>
            <p>{{cmessage}}</p>
            <p>{{cmovies}}</p>
            <p>遍历Array</p>
            <ul>
                <li v-for="(item,index) in cmovies">{{index}} - {{item}}</li>
            </ul>
        </div>
    </template>

    <div id="app">
        <tmp :cmessage="message" :cmovies="movies"></tmp>
    </div>

    <script>

        Vue.component('tmp',{
           template: '#tmp',
           data(){
               return {}
           },
           props:['cmessage','cmovies']
        });

        const vm = new Vue({
            el: '#app',
            data: {
                message: '电影列表',
                movies: ['钢铁侠','美国往事','火星救援','阿甘正传']
            }
        })
    </script>
</body>
</html>
2.传递复杂数据
  • props属性不仅可以声明为数组,还可以声明为对象类型,这样可以进一步对变量作一些属性要求,并且每个变量还可以声明为一个对象,赋予更多的属性
  • 可以对props里声明的变量做类型要求,是否有默认值等,其中type可传的类型有[String,Array,Object,Number,Boolean,Date]等等
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父组件传子组件</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>

    <template id="tmp">
        <div>
            <p>获取到父组件的message是:{{cmessage}}</p>
            <p>获取到父组件的movies是:{{cmovies}}</p>
            <p>获取到父组件的cperson是:{{cperson}}</p>
        </div>
    </template>

    <div id="app">
        <tmp :cmessage="message" :cmovies="movies" :cperson="person"></tmp>
    </div>

    <script>

        Vue.component('tmp',{
           template: '#tmp',
           data(){
               return {}
           },
           props:{
               cmessage: {
                   type: String,
                   default: ''
                   // 可以声明required属性,如果父组件没传值将会报错
                   // required:true
               },
               cmovies: {
                   type: Array,
                   default: function () {
                       return []
                   }
               },
               cperson: {
                   type: Object,
                   default: function () {
                       return {}
                   }
               }
           }
        });

        const vm = new Vue({
            el: '#app',
            data: {
                message: '文本内容',
                movies: ['钢铁侠','美国往事','火星救援','阿甘正传'],
                person: {
                    name: '小明',
                    age: '18',
                    sex: '男',
                    hobbies: ['篮球','羽毛球','乒乓球']
                }
            }
        })
    </script>
</body>
</html>
二、子传父this.$emit
  • 子传父是需要自定义事件,并通过$emit发送给父组件
  • 首先注册局部组件,并声明了一组分类数据通过data()函数返回
  • 模板里遍历整个Array并创建对应按钮,每个按钮通过v-on绑定了函数,组件可以声明自己的函数,点击按钮时会触发该函数
  • 函数里通过 this.$emit(‘itemclick’,category)发出自己信号,第一个参数表示发射给父组件的变量名,第二参数为对应的值
  • 然后父组件使用子组件<tmp>,通过v-on监听刚才子组件发射的变量名,并绑定父组件的方法事件pbtnclick,点击按钮则会出发该事件,至此完成了子传父
  • 注意@itemclick="pbtnclick"中参数可以省略,也可以声明@itemclick=“pbtnclick(category)”
  • 注意方法名尽量不要使用驼峰命名
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子传父</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>

    <!-- 子组件模板 -->
    <template id="tmp">
        <div>
            <p>{{cmessage}}</p>
            <button v-for="category in categoryList" @click="btnclick(category)">{{category.name}}</button>
        </div>
    </template>

    <!-- 父组件模板 -->
    <div id="app">
        <tmp @itemclick="pbtnclick" :cmessage="message"></tmp>
    </div>

    <script>

        const app = new Vue({
            el: '#app',
            data:{
                message: '提示信息'
            },
            // 注册局部组件
            components:{
                tmp:{
                    template: '#tmp',
                    data: function () {
                        return {
                            categoryList:[
                                {id:1,name:'手机数码'},
                                {id:2,name:'家用电器'},
                                {id:3,name:'生活用品'},
                                {id:4,name:'时尚穿搭'}]
                        }
                    },
                    props:['cmessage'],
                    methods:{
                        btnclick:function (category) {
                            console.log(category);
                            // 向父组件发射事件
                            this.$emit('itemclick',category);
                        }
                    }
                }
            },
            methods: {
                pbtnclick:function (category) {
                    console.log("父组件接收到的内容:"+JSON.stringify(category));
                }
            }
        });
    </script>
</body>
</html>
三、父子组件引用对象访问
  • 父子组件之间既可以进行通信,也可以通过获得当前引用对象来访问其中内容(注意只能进行访问,不能修改内容,例如修改变量值等)
1.父组件通过引用对象访问子组件
  • 通过this.$children可以获得当前子组件对象内容
  • 访问其中内容必须通过下标指定访问哪一个children,因为可能有多个子组件被声明使用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父访问子-引用对象形式访问</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>

    <template id="tmp">
        <div>
            <p>{{msg}}</p>
        </div>
    </template>

    <div id="app">
        <tmp></tmp>
        <button @click="getRefContent">获取子组件引用对象</button>
    </div>

    <script>
        const app = new Vue({
            el: '#app',
            data:{},
            methods:{
                getRefContent(){
                    console.log("子组件对象内容:");
                    console.log(this.$children);
                    console.log("调用子组件方法: "+this.$children[0].showMsg());
                    console.log("获取子组件变量: "+this.$children[0].msg)
                }
            },
            components:{
                tmp:{
                    template: '#tmp',
                    data(){
                        return {
                            msg: '这是子组件消息'
                        }
                    },
                    methods: {
                        showMsg(){
                            console.log("子组件showMsg方法");
                        }
                    }
                }
            }
        });
    </script>
</body>
</html>

**注意:**通过下标来访问某一个组件内容是不可靠的,因为可能会有新的组件被声明使用,例如:

 <div id="app">
     	<!-- 新增了一个子组件cpn,这时放在两个tmp中间,那么通过this.children[1]去访问第二个tmp就不可靠了,因为它变成了cpn -->
        <tmp></tmp>
     	<cpn></cpn>
        <tmp></tmp>
        <button @click="getRefContent">获取子组件引用对象</button>
    </div>

那么,其实这种情况也是有解决办法的,那就是通过$refs进行访问,修改一些代码:

<div id="app">
    <tmp></tmp>
    <!-- 这里通过ref指定了引用名 -->
    <tmp ref="aaa"></tmp>
    <button @click="getRefContent">获取子组件引用对象</button>
</div>
<script>
        const app = new Vue({
            el: '#app',
            data:{},
            methods:{
                getRefContent(){
                    console.log("子组件对象内容:");
                    console.log(this.$children);
                    // console.log("调用子组件方法: "+this.$children[0].showMsg());
                    // console.log("获取子组件变量: "+this.$children[0].msg)
                    console.log(this.$refs.aaa.msg);
                }
            },
            components:{
                tmp:{
                    template: '#tmp',
                    data(){
                        return {
                            msg: '这是子组件消息'
                        }
                    },
                    methods: {
                        showMsg(){
                            console.log("子组件showMsg方法");
                        }
                    }
                }
            }
        });
    </script>

通过ref给组件指定引用名,然后方法里通过this. r e f s 引 用 调 用 指 定 的 组 件 名 就 可 以 获 取 其 中 内 容 , 这 样 , 无 论 组 件 发 生 怎 样 的 变 化 , 都 可 以 确 保 访 问 正 确 的 子 组 件 。 refs引用调用指定的组件名就可以获取其中内容,这样,无论组件发生怎样的变化,都可以确保访问正确的子组件。 refs访refs默认是个空的引用,必须配合组件上指定引用的名称方可使用

2.子组件通过引用对象访问父组件
  • 子组件通过this.$parent获取父组件对象内容
  • 子组件childrentmp通过this.$parent获取的是它的上一级父组件parenttmp内容
  • 而父组件parenttmp通过this.$parent获取的是它的上一级父组件内容是vue实例(new Vue这个实例对象)
  • 如果childrentmp想获取根属性,可以通过this.$root引用获取
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子访问父-引用对象形式访问</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>

    <template id="childrentmp">
        <div style="width: 500px;height: 300px;background-color: #CCE8EB">
            <h2>{{ccontent}}</h2>
            <button @click="getParent">获取父组件内容</button>
        </div>
    </template>

    <template id="parenttmp">
        <div style="width: 600px;height: 500px;background-color: #cad9ea">
            <h1>{{pcontent}}</h1>
            <button @click="getOriginParent">获取父组件内容</button>
            <!-- 引用子组件 -->
            <childrentmp></childrentmp>
        </div>
    </template>

    <div id="app">
        <parenttmp></parenttmp>
    </div>

    <script>
        const app = new Vue({
            el:'#app',
            data:{
                message: 'vue实例'
            },
            components:{
                parenttmp:{
                    template:'#parenttmp',
                    data(){
                        return {
                            pcontent: '这是父组件内容',
                            name: '父组件'
                        }
                    },
                    methods: {
                        getOriginParent(){
                            console.log(this.$parent);
                        }
                    },
                    components: {
                        childrentmp:{
                            template:'#childrentmp',
                            data(){
                                return {
                                    ccontent: '这是子组件内容',
                                }
                            },
                            methods:{
                                getParent(){
                                    console.log(this.$parent);
                                    // 获取根对象,即vue实例
                                    console.log(this.$root);
                                }
                            }
                        }
                    }
                }
            }
        });
    </script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值