组件中常见的通信方式

一、父组件向子组件传递

父组件通过props方式向子组件传递父组件的数据
props是单向绑定,只能父传子
props只读,不可对props进行修改,要修改只能将新数据传递给父组件,父组件修改数据后,再传递给子组件

  • 给子组件通过自定义属性绑定父组件需要传递的数据
  • 子组件通过props来接收父组件传递的数据,props是数组
props1.png
props2.png
  • 父组件代码块
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <hello-world :msg="msg" :info="info" ></hello-world>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
  name: 'HomeView',
  data: function () {
    return {
      msg: '这是父组件的msg',
      info: '这是父组件的info',
    }
  },
  components: {
    HelloWorld
  }
}
</script>

  • 子组件代码块
<template>
  <div class="hello">
    <h1>{{msg}}</h1>
    <h1>{{info}}</h1>  
  </div>
</template>

<script>
export default {
  props: ['msg', 'info'],
  name: 'HelloWorld',
}
</script>

二、子组件向父组件传递

  • 注册自定义事件 this.$emit() 第一个参数是自定义事件名,第二个参数是需要传的参数(多个参数就传数组或者对象)
  • v-on 监听子组件上面的自定义事件 如果事件不写小括号,那么methods中的第一个参数就是自定义事件中传递过来的值;如果需要额外传递参数,则需要使用$event来接收自定义事件传的参数
$emit1.png
$emit2.png
  • 子组件代码块
<template>
  <div class="hello">
    <h1>{{msg}}</h1>
    <h1>{{info}}</h1>
    <input type="button" value="子传父" @click="sendFmsg">
  </div>
</template>

<script>
export default {
  props: ['msg', 'info'],
  name: 'HelloWorld',
  data: function () {
    return {
      fmsg: '我是子组件的fmsg'
    }
  },
  methods: {
    sendFmsg () {
      this.$emit('handle-fmsg', this.fmsg)
    }
  }
}
</script>

<style scoped lang="less">

</style>

  • 父组件代码块
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <hello-world :msg="msg" :info="info" v-on:handle-fmsg="getfmsg" ></hello-world>
    <h1>{{fmsg}}</h1>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data: function () {
    return {
      msg: '这是父组件的msg',
      info: '这是父组件的info',
      fmsg: ''
    }
  },
  methods: {
    getfmsg (val) {
      this.fmsg = val
    }
  },
  components: {
    HelloWorld
  }
}
</script>

三、provide/inject

祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题。父组件的所有后代组件都可以通过inject获取父组件通过provide传递的数据。

provide1.png
provide2.png
  • 父组件代码块
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <hello-world></hello-world>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data: function () {
    return {
      info: '我是父组件的info',
      msg: '我是父组件的msg'
    }
  },
  provide: function () {
    return {
      info: this.info,
      msg: this.msg
    }
  },
  components: {
    HelloWorld
  }
}
</script>
  • 子组件代码块
<template>
  <div class="hello">
    <h1>{{info}}</h1>
    <h2>{{msg}}</h2>
    <son-com></son-com>
  </div>
</template>

<script>
import sonCom from '@/components/sonCom.vue'
export default {
  inject: ['info', 'msg'],
  name: 'HelloWorld',
  components: {
    sonCom
  }
}
</script>
  • 孙组件代码块
<template>
  <div class="son">
    <h1>{{info}}</h1>
    <h2>{{msg}}</h2>
  </div>
</template>

<script>
export default {
  inject: ['info', 'msg'],
}
</script>

parent和children

parent和$children这两种方法是直接获取组件实例,可以直接调组件的方法或者数据

  • 在子组件中打印this.$parent,输出结果是父组件的实例,是个对象,里面有父组件中的数据info,那我们在子组件就可以直接调用
$parent1.png
  • 在父组件中打印this.$children,输出结果是子组件的实例,是个数组,里面有子组件中的数据msg,那我们在父组件就可以直接调用
$children1.png
pc1.png
pc2.png
  • 父组件代码块
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <hello-world></hello-world>
    <h1>{{msg}}</h1>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data: function () {
    return {
      info: '我是父组件的info',
      msg: ''
    }
  },
  mounted () {
    console.log(this.$children)
    this.msg = this.$children[0].msg
  },
  components: {
    HelloWorld
  }
}
</script>

  • 子组件代码块
<template>
  <div class="hello">
    <h2>{{info}}</h2>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data: function () {
    return {
      info: '',
      msg: '我是子组件的msg'
    }
  },
  mounted () {
    console.log(this.$parent)
    this.info = this.$parent.info
  }
}
</script>

<style scoped lang="less">

</style>

五、vuex

  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态,解决多组件数据通信

vuex的五个属性

state: 定义全局都可使用的数据

mutations : 使用mutations里面的方法来修改state里面的数据(类似于methods)

getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据),对state里面的数据进行某些处理

actions: 可以使用commit触发mutations里面的方法,也可以发起异步请求,进行异步操作

modules: 对各个模块进行拆分,让每个数据都有与之相关独立的mutations、getters和actions

在项目中配置vuex

  • 在创建项目进行配置的时候,将vuex选上,就很方便,可以省去很多操作
vuex1.png

代码


vuex2.png

效果


vuex3.png

vuex代码块

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    msg: 'vue里的全局数据',
    num: 1
  },
  // 相当于对state里的数据进行运算得到的数据,类似计算属性对data数据的处理
  getters: {
    numDb (state) {
      return state.num * 2
    }
  },
  // 定义修改state里面的数据的方法
  mutations: {
    updateMsg (state) {
      state.msg = '修改之后的msg数据'
    },
    updateNum (state, info) {
      state.num += info
    }
  },
  // actions中的方法触发mutations中的方法从而改变state里的数据。也可以在这里执行异步操作
  actions: {
    actionsUpdateNum (c, val) {
      c.commit('updateNum', val)
    }
  },
  modules: {
  }
})

子组件代码块

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h2>state的msg:{{$store.state.msg}}</h2>
    <button @click="updateMsg">修改msg</button>
    <h2>state的num:{{$store.state.num}}</h2>
    <button @click="updateNum(5)">+5</button>
    <button @click="updateNum(10)">+10</button>
    <h2>getters处理之后的num:{{$store.getters.numDb}}</h2>
    <button @click="actionsUpdateNum(1)">actions修改</button>
  </div>
</template>

<script>
import store from '@/store/index'
export default {
  store,
  methods: {
    updateMsg () {
      // 触发vuex的mutations中的方法修改msg
      this.$store.commit('updateMsg')
    },
    // 组件methods通过调用vuex实例的commit方法触发vuex中mutations方法
    updateNum (info) {
      this.$store.commit('updateNum', info)
    },
    // 组件methods通过调用vuex实例的dispatch方法触发vuex中actions方法
    actionsUpdateNum (val) {
      this.$store.dispatch('actionsUpdateNum', val)
    }
  }
}
</script>

以上几种是比较常见的方法,记住上面的方法,可以应对大部分组件的通信,还有其他方法的也可以一起分享!

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

推荐阅读更多精彩内容