原文连接:https://www.jianshu.com/bookmarks
父组件通过 props 的方式向子组件传递数据,而通过 emit() 子组件可以向父组件通信。
下面通过一个例子说明父组件如何向子组件传递数据:
在子组件article.vue中如何获取父组件 section.vue 中的数据 articles:['红楼梦', '西游记','三国演义']
// section父组件
// 子组件 article.vue
{{item}}
总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。
对于emit () 我自己的理解是这样的 ,emit绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件通过v-on监听并接收参数。 通过一个例子,说明子组件如何向父组件传递数据。
在上个例子的基础上, 点击页面渲染出来的ariticle的item, 父组件中显示在数组中的下标
// 父组件中
{{currentIndex}}
// 在子组件中
{{item}}
上面这张图片是vue官方的解释,通过parent \ children就可以访问组件的实例,拿到实例代表什么?代表可以访问此组件的所有方法和data。接下来就是怎么实现拿到指定组件的实例
// 父组件中
{{msg}}
// 子组件中
{{messageA}}
获取父组件的值为: {{parentVal}}
要注意边界情况,如在#app上拿 parent 得到的是 newValue 的实例,在这实例上在拿parent得到的是undefind,而在最底层的子组件拿children是个空数组,也要注意得到parent和children的值不一样,children 的值是数组,而$parent是个对象
上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍;
二者皆不能用于非父子组件之间的通信。
provide/ inject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。
注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据
举例验证
接下来就用一个例子来验证上面的描述:
假设有三个组件: A.vue、B.vue、C.vue 其中 C是B的子组件,B是A的子组件
// A.vue
// B.vue
{{demo}}
// C.vue
{{demo}}
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据, 我们看一个ref 来访问组件的例子:
// 子组件 A.vue
export default {
data() {
return {
name: "Vue.js"
};
},
methods: {
sayHello() {
console.log("hello");
}
}
};
// 父组件 app.vue
eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。
eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难
在Vue的项目中怎么使用eventBus来实现组件之间的数据通信呢?具体通过下面几个步骤
1. 初始化
首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它.
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
2. 发送事件
假设你有两个组件: additionNum 和 showNum, 这两个组件可以是兄弟组件也可以是父子组件;这里我们以兄弟组件为例:
// addtionNum.vue 中发送事件
// showNum.vue 中接收事件
计算和: {{count}}
这样就实现了在组件addtionNum.vue中点击相加按钮, 在showNum.vue中利用传递来的 num 展示求和的结果.
4. 移除事件监听者
如果想移除事件的监听, 可以像下面这样操作
import { eventBus } from'event-bus.js'
EventBus.$off('addition'
, {})
Vuex 是一个专为 Vue.js 应用程序开发的 状态管理 模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上
// 父组件
// 子组件childA
我是A组件
因为你点了B,所以我的信息发生了变化:{{BMessage}}
// 子组件 childB
我是B组件
因为你点了A,所以我的信息发生了变化:{{AMessage}}
vuex的store,js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
// 初始化A和B组件的数据,等待获取
AMsg: '',
BMsg: ''
}
const mutations = {
receiveAMsg(state, payload) {
// 将A组件的数据存放于state
state.AMsg = payload.AMsg
},
receiveBMsg(state, payload) {
// 将B组件的数据存放于state
state.BMsg = payload.BMsg
}
}
export default new Vuex.Store({
state,
mutations
})
这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。
通过 window.localStorage.getItem(key)
获取数据
通过 window.localStorage.setItem(key,value)
存储数据
注意用JSON.parse() / JSON.stringify() 做数据格式转换
localStorage / sessionStorage可以结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题.
现在我们来讨论一种情况, 我们一开始给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?
// app.vue
// index.vue
// childCom1.vue
name: {{ name}}
childCom1的$attrs: {{ $attrs }}
// childCom2.vue
age: {{ age}}
childCom2: {{ $attrs }}
总结
常见使用场景可以分为三类:
父子组件通信: props; parent / children; provide / inject ; ref ;attrs / listeners
兄弟组件通信: eventBus ; vuex
跨级通信: eventBus;Vuex;provide / inject 、atrs / listeners