Vue组件-父子组件传递数据

一.父子组件

1.什么是父子组件?
 就是在组件中又定义了其他组件
 其实局部组件就是最简单的子组件,因为把Vue实例看做一个大的父组件
 在Vue中的局部组件就相当于大组件中的小组件,这就是最简单的局部组件

2.如何定义其他父子组件
 自定义组件可以使用data,可以使用methods,当然自定义组件还可以使用components
 如果把创建的Vue实例对象当做父组件,那么在Vue实例对象中创建的局部组件components就是子组件;如果在局部组件中再次创建components就是孙子组件,此时的Vue实例对象就相当于爷爷组件,在Vue实例对象中创建的局部组件components就是父组件;

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

<template id="father">
    <div>
        <p>我是父组件</p>
        <def></def>
    </div>
</template>
<template id="son">
    <div>
        <p>我是子组件</p>
    </div>
</template>

<script>
    //创建Vue的实例对象
    let vue = new Vue({
        el:"#app",
        data:{ },
        methods:{},
        computed:{  },
        //专门用于定义局部组件
        components:{
            "abc":{
                template: "#father",
                components:{
                    "def":{
                        template: "#son"
                    }
                }
            }
        }
    });
</script>

二.父组件向子组件传递数据(data)

1.如何传递数据
 1.1在父组件中通过v-bind传递数据
   传递格式 v-bind:自定义接收名称 = "要传递数据"
 1.2在子组件中通过props接收数据
    接收格式 props: ["自定义接收名称"]

<div id="app">
   <father></father>
</div>
<template id="father">
   <div>
       <!--注意点: 组件是可以使用自己的数据的-->
       <p>{{name}}</p>
       <p>{{age}}</p>
       <!--这里将父组件的name通过parentname传递给了子组件-->
       <son :parentname="name" :abc="age"></son>
   </div>
</template>
<template id="son">
   <div>
       <!--这里通过parentname使用了父组件传递过来的数据-->
       <p>{{parentname}}</p>
       <p>{{abc}}</p>
   </div>
</template>
<script>
// 父组件
   Vue.component("father", {
       template: "#father",
       data: function(){
         return {
             name: "yaxi",
             age: 20
         }
       },
       // 子组件
       components: {
           "son": {
               template: "#son",
               // 这里通过parentname接收了父组件传递过来的数据
               props: ["parentname", "abc"]
           }
       }
   });
   let vue = new Vue({
       el: '#app',
       data: { },
       methods: { },
       computed: { },
       components: {}
   });
</script>

三.父组件向子组件传递方法(methods)

1.如何传递方法
 1.1在父组件中通过v-on传递方法
   传递格式 v-on:自定义接收名称 = "要传递方法"
 1.2在子组件中自定义一个方法
 1.3在自定义方法中通过 this.$emit('自定义接收名称');触发传递过来的方法

<div id="app">
    <father></father>
</div>
<template id="father">
    <div>
        <button @click="say">我是按钮</button>
        <!--这里通过parentsay将父组件的say方法传递给子组件-->
        <son @parentsay="say"></son>
    </div>
</template>
<template id="son">
    <div>
        <button @click="sonFn">我是按钮</button>
    </div>
</template>

<script>
    // 父组件
    Vue.component("father", {
        template: "#father",
        methods: {
            say(){
                alert("2541873074@qq.com")
            }
        },
        // 子组件
        components: {
            "son": {
                template: "#son",
                methods:{
                    sonFn(){
                      this.$emit("parentsay");
                    }
                }
            }
        }
    });

    let vue = new Vue({
        el: '#app',
        data: {   },
        methods: { },
        computed: { },
        components: {  }
    });
</script>

四.子组件向父组件传递数据(data)

1.如何将子组件数据传递给父组件
 父组件先传递一个方法给子组件,子组件调用这个方法的时候传递参数给父组件,传递参数就是传递数据

<div id="app">
    <father></father>
</div>
<template id="father">
    <div>
        <button @click="say">我是按钮</button>
        <!--这里通过parentsay将父组件的say方法传递给子组件-->
        <son @parentsay="say"></son>
    </div>
</template>
<template id="son">
    <div>
        <button @click="sonFn">我是按钮</button>
    </div>
</template>

<script>
    // 父组件
    Vue.component("father", {
        template: "#father",
        methods: {
            //data:接受从子组件传递的参数
            say(data){
                console.log(data);
            }
        },
        // 子组件
        components: {
            "son": {
                template: "#son",
                methods:{
                    sonFn(){
                        /*
                         this.$emit的第一个参数:需要调用的函数名称
                         this.$emit的后续的参数:给调用的函数传递的参数
                         */
                        this.$emit("parentsay","鱿小鱼");
                    }
                }
            }
        }
    });
 
    let vue = new Vue({
        el: '#app',
        data: {},
        methods: {},
        computed: {},
        components: {}
    });
</script>

五.组件中的命名注意点

1.注册组件的时候使用“驼峰命名”,使用组建的时候转换成“短横线分割命名”
例如:注册时:myFather -- 使用时:my-father
2.在传递参数的时候如果想使用“驼峰名称”,那么就必须写“短横线分割命名”
例如:传递时:parent-name="name" -- 接受时:props["parentName"]
3.在传递方法的时候不同使用“驼峰名称”,只能使用“短横线分割命名”
例如:传递时:@parent-say="say" -> 子组件的methods中:this.$emit("parent-say");

六.数据和方法的多级传递

在Vue中如果儿子想使用爷爷的数据,必须一层一层向下传递
在Vue中如果儿子想使用爷爷的方法,必须一层一层向下传递

<div id="app">
    <grandfather></grandfather>
</div>
<template id="grandfather">
    <div>
        <p>{{name}}</p>
        <button @click="say">我是按钮</button>
        <father :gfname="name" @gfsay="say"></father>
    </div>
</template>
<template id="father">
    <div>
        <p>{{gfname}}</p>
        <button @click="fatherFn">我是按钮</button>
        <son :fname="gfname" @fsay="fatherFn"></son>
    </div>
</template>
<template id="son">
    <div>
        <p>{{fname}}</p>
        <button @click="sonFn">我是按钮</button>
    </div>
</template>

<script>
    // 爷爷组件
    Vue.component("grandfather", {
        template: "#grandfather",
        data:function(){
            return{
                name:"yaxi"
            }
        },
        methods:{
            say(){
                console.log("我是爷爷的方法");
            }
        },
        // 爸爸组件
        components: {
            "father": {
                template: "#father",
                props:["gfname"],
                methods:{
                    fatherFn(){
                       this.$emit("gfsay");
                    }
                },
                //儿子组件
                components:{
                    "son":{
                        template:"#son",
                        props:["fname"],
                        methods:{
                            sonFn(){
                                this.$emit("fsay");
                            }
                        }
                    }
                }
            }
        }
    });

    let vue = new Vue({
        el: '#app',
        data: {},
        methods: {},
        computed: { },
        components: {}
    });
</script>

注意点:
1.如果想要在子组件中使用父组件中的数据,那么必须通过父组件传递
2.如果想要在子组件中使用祖先组件中的数据, 那么就必须一 层一 层的传递
3.兄弟组件之间不能直接传递数据,如果兄弟组件之间想要传递数据,那么就必须借助父组件
虽然通过借助父组件能够实现兄弟组件之间的数据传递,但是这种方式非常的复杂,非常的不推荐
那么当前在企业开发中我们遇到了两个问题:
1.如果想要在子组件中使用祖先组件中的数据,那么就必须一层一层的传递(非常麻烦)
2.兄弟组件之间不能直接传递数据,如果兄弟组件之间想要传递数据,那么就必须借助父组件(非常麻烦)
解决方案:使用Vuex


七.匿名插槽和具名插槽

1.默认情况下是不能在使用子组件的时候,给子组件动态添加内容,如果想在使用子组的时候,给子组件动态添加内容,那么就必须使用插槽
 <slot></slot>标签就是插槽,以后使用者可以根据自己的需求来填补;
注意点
  插槽可以指定默认数据,如果使用者没有填补插槽,那么就会显示默认数据,如果使用者填补了这个插槽,就会利用使用者填补的数据替换整个默认数据;
  插槽可以指定名称,默认情况下如果没有指定名称,我们就称之为匿名函数;
  默认情况下有多少个匿名插槽,我们填充的数据就会被拷贝多少份,导致了所有插槽中填充的内容都是一样的

<div id="app">
    <father></father>
</div>
<template id="father">
    <div>
        <!--需求:在使用子组件的时候给子组件动态的添加一下内容-->
       <son>
            <div>我是追加的内容1</div>
            <div>我是追加的内容2</div>
            <div>我是追加的内容3</div>
       </son>
    </div>
</template>
<template id="son">
    <div>
        <div>我是头部</div>
        <!--匿名插槽的特点:有多少个匿名插槽,填充的数据就会拷贝几份
                            虽然我们可以指定多个匿名插槽,但企业开发中推进只写一个匿名插槽
        -->
        <slot>我是默认数据</slot>
        <div>我是底部</div>
    </div>
</template>

效果:

2.如果我们想给不同的插槽中填充不同的内容怎么办呢?  这个时候就可以使用具名插槽
具名插槽的使用:
  通过插槽的name属性给插槽指定名称
  在使用时可以通过slot=" name"方式,指定当前内容用于替换哪个插槽
  注意点:如果没有指定要替换哪个插槽中的内容,则不会被替换
  注意点: slot 属性在Vue2.6中已经被废弃,Vue2. 6之后使用v-slot指令替代slot属性

div id="app">
    <father></father>
</div>
<template id="father">
    <div>
       <son>
            <!--通过slot属性告诉Vue,当前的内容是要填充到哪一个插槽中的-->
            <div slot="one">我是追加的内容1</div>
            <div slot="one">我是追加的内容111</div>
            <div slot="two">我是追加的内容2</div>
            <div slot="two">我是追加的内容222</div>
       </son>
    </div>
</template>
<template id="son">
    <div>
        <div>我是头部</div>
        <slot name="one">我是one默认数据</slot>
        <slot name="two">我是two默认数据</slot>
        <div>我是底部</div>
    </div>
</template>

效果:

八.v-slot指令和作用域插槽

1.什么是v-slot指令?
  v-slot指令是Vue2. 6中用于替代slot属性的一个指令
  在Vue2.6之前,我们通过slot属性告诉Vue当前内容填充到哪一个具名插槽
  从Vue2.6开始,我们通过v-slot指令告诉Vue当前内容填充到哪一个具名插槽
  注意点: v-slot指令只能用在template标签上,#可以使用#号替代v-slot指令

<div id="app">
    <father></father>
</div>
<template id="father">
    <div>
       <son>
           <template #one>
               <div>我是追加的内容1</div>
               <div>我是追加的内容11</div>
           </template>
           <template #two>
               <div>我是追加的内容2</div>
               <div>我是追加的内容22</div>
           </template>
       </son>
    </div>
</template>
<template id="son">
    <div>
        <div>我是头部</div>
        <slot name="one">我是one默认数据</slot>
        <slot name="two">我是two默认数据</slot>
        <div>我是底部</div>
    </div>
</template>

效果:

2..什么是作用域插槽
  作用域插槽就是带数据的插槽就是让父组件在填充子组件插槽内容时也能使用子组件的数据
3.如何使用作用域插槽
  3.1在slot中通过v-bind:数据名称='数据名称”方式暴露数据
  3.2在父组件中通过<template slot-scope=" 作用域名称">接收数据
  3.2.1在父组件中还可以通过<template v-slot:插槽名称=" 作用域名称">接收数据匿名插槽的名称是default
  3.2.2在父组件中也可以通过<template #插槽名称=" 作用域名称">接收数据在子组件中指定插槽名称 name="插槽名称"
4.作用域插槽的应用场景:子组件提供数据,父组件决定如何渲染

<div id="app">
    <father></father>
</div>
<template id="father">
    <div>
       <son>
          <!--slot-scope="abc" 接受子组件插槽暴露的数据-->
          <!--
                <template slot-scope="abc">
                    <li v-for="(value,index) in abc.names">{{value}}</li>
                </template>
            -->
            <!--
               <template v-slot:default="abc">
                    <li v-for="(value,index) in abc.names">{{value}}</li>
               </template>
            -->
           <template #one="abc">
               <li v-for="(value, index) in abc.names">{{value}}</li>
           </template>
       </son>
    </div>
</template>
<template id="son">
    <div>
        <div>我是头部{{name}}</div>
        <!--将子组件中的names通过names暴露给父组件-->
        <slot name="one" v-bind:names="names">我是默认数据{{names}}</slot>
        <div>我是底部</div>
    </div>
</template>
<script>
    // 父组件
    Vue.component("father", {
        template: "#father",
        //子组件
        components: {
            "son": {
                template: "#son",
                data:function () {
                    return{
                        names:["zs","ls","ww","zl"]
                    }
                }
            }
        }
    });
 let vue = new Vue({
        el: '#app',
});
</script>

效果:
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341