Vue父子组件通信总结

感觉Vue中父子传参的方式,实在是太多了,于是做一个小总结,只是总结我所知道的。

1.父传子

基本就用一个方式,props

父亲通过在 标签 中写入需要传入的数据。

<!--father.vue-->
<template>
    <div>
        我是爸爸,下面是儿子
        <son title='儿子' :selected='selected'></son>
    </div>
</template>

儿子在 实例中的 props 选项中获取

//son.vue
export default {
    name:'son',
    props:{
        selected:{
            type:Boolean
        },
        title:{
            type:String
        }
    }
}

2.子传父

# update:my-prop-name 模式

Vue 是单项数据流,所以不允许 儿子 直接修改父亲的数据,也不允许儿子直接修改自己的props

假设一个情况,点击儿子,儿子需要改变 selected 的状态。

儿子方面

触发点击事件后, 让儿子触发一个 update 事件,把新的 selected 传出去

<!--son.vue-->
<template>
    <div class="son" @click="onClick">
        title:{{title}} selected:{{selected}}
    </div>
</template>
<script>
export default {
  name: "son",
  props: {
    selected: {
      type: Boolean
    },
    title: {
      type: String
    }
  },
  methods: {
    onClick() {
      this.$emit("update:selected", !this.selected); //关键点
    }
  }
};
</script>

<style>
.son {
  border: 1px solid red;
}
</style>

父亲方面

在标签中监听 update事件,并将传过来的 $event付给 selected,这样就完成了一次传参。

<!--father.vue-->
<template>
    <div>
        我是爸爸,下面是儿子
        <son title='儿子' :selected='selected' @update:selected='selected=$event'></son> 
        <!--关键点-->
    </div>
</template>

<script>
import Son from "./son";
export default {
  name: "father",
  components: {
    Son
  },
  data() {
    return {
      selected: true
    };
  }
};
</script>

简单方式

.sync 修饰符

<!--father.vue-->
<template>
    <div>
        我是爸爸,下面是儿子
        <son title='儿子' :selected.sync='selected'></son> 
        <!--关键点-->
    </div>
</template>

# $parents API

儿子方面

this.$parent中可以获取到 父组件 的 data 数据 ,直接进行修改,是不是很刺激。

methods: {
    onClick() {
      this.$parent.selected = !this.$parent.selected;
    }
  }

虽然刺激,但是,我建议调用父组件的函数,来切换状态。

父亲方面

//father.vue
export default {
  name: "father",
  components: {
    Son
  },
  data() {
    return {
      selected: true
    };
  },
  methods: {
    changeSelected() {
      this.selected = !this.selected;
    }
  }
};

儿子方面

//son.vue 
methods: {
    onClick() {
      this.$parent.changeSelected();
    }
  }

# EventBus

如果只是一个父亲,一个儿子上面的方法非常的简单实用,但是如果是祖孙三代传参呢?上面的方法就很麻烦了。

具体怎么麻烦,可以看一下我的这篇文章,用原始的方法造 tabs轮子:https://zhuanlan.zhihu.com/p/39601572

废话不多说,开始用 EventBus做一个简单的 tabs组件。

#app.vue
<template>
  <div id="app">
    <tab selected='news'>
      <tab-item name='news'>新闻</tab-item>
      <tab-item name='car'>汽车</tab-item>
      <tab-item name=‘code’>代码</tab-item>

      <tab-pane name='news'>新闻列表</tab-pane>
      <tab-pane name='car'>汽车列表</tab-pane>
      <tab-pane name=‘code’>代码列表</tab-pane>
    </tab>
  </div>
</template>

<script>
import Tab from "./components/tabs.vue";
import TabItem from "./components/tab-item";
import TabPane from "./components/tab-pane";

export default {
  name: "app",
  components: {
    Tab,
    TabItem,
    TabPane
  }
};
</script>
# tabs.vue
<template>
    <div>
        <slot></slot>
    </div>
</template>

<script>
import TabItem from "./tab-item.vue";
import Vue from "vue";  //引入VUE
export default {
  name: "tab",
  props: {
    selected: {
      type: [Number, String]
    }
  },
  data() {
    return {
      eventBus: new Vue() // 创建 eventBus
    };
  },
  provide() {
    return {
      eventBus: this.eventBus // 提供 eventBus
    };
  },
  mounted() {
    this.eventBus.$emit("update:selected", this.selected); 
      //发布消息,告诉大家,现在的selected是啥
  }
};
</script>

<style>
</style>
# tabs-item.vue
<template>
    <div @click="onClick" :class="{active}">
        <slot/>
    </div>
</template>

<script>
export default {
  name: "tab-item",
  props: {
    name: {
      type: [String, Number]
    }
  },
  inject: ["eventBus"], //注入 eventBus
  data() {
    return {
      active: false
    };
  },
  created() {
    this.eventBus.$on("update:selected", newSelected => {
      this.active = this.name === newSelected;
    }); //接收消息,如果newselected 和我的 name 相同,那么我就被选中了
  },
  methods: {
    onClick() {
      this.eventBus.$emit("update:selected", this.name);
        //发布消息,如果点击了我,我就告诉大家,我被选中了
    }
  }
};
</script>

<style>
.active {
  color: red;
}
</style>
# tab-pane.vue
<template>
  <div v-if="active" class="pane">
    <slot/>
  </div>
</template>

<script>
export default {
  name: "tab-pane",
  props: {
    name: {
      type: [String, Number]
    }
  },
  data() {
    return {
      active: false
    };
  },
  inject: ["eventBus"],//注入 eventBus
  created() {
    this.eventBus.$on("update:selected", newSelected => {
      this.active = this.name === newSelected;
    });
      //接收消息,如果newselected 和我的 name 相同,那么我就被选中了
  }
};
</script>

<style>
.pane {
  color: red;
}
</style>

# 灵活运用 provide inject

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

推荐阅读更多精彩内容

  • 前言 您将在本文当中了解到,往网页中添加数据,从传统的dom操作过渡到数据层操作,实现同一个目标,两种不同的方式....
    itclanCoder阅读 25,720评论 1 12
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,043评论 0 29
  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 10,973评论 4 129
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,193评论 0 6
  • VUE介绍 Vue的特点构建用户界面,只关注View层简单易学,简洁、轻量、快速渐进式框架 框架VS库库,是一封装...
    多多酱_DuoDuo_阅读 2,684评论 1 17