vue组件通信有父传子,子传父,非父子关系
父传子
先说下父组件传给子组件参数
父组件给组件值传值可以通过在父组件的子标签中添加自定义属性名 绑定要传输的参数,
之后子组件通过props来接收这个参数
props的用法有三个
props: ['childCom']
props: {
childCom: String //这里指定了字符串类型,如果类型不一致会警告的哦
}
props: {
childCom: {
type: String,
default: 'sichaoyun'
}
}
有两点要注意的是
-
不应该在组件内部改变prop,这样会破坏单项的数据绑定,导致数据流难以理解,如果有这样的需求,可以通过过 data 属性接收或使用 computed 属性进行转换。
-
props 传递的 数组和对象是通过引用来传入的,所以当子组件中改变这个对象或数组,父组件的状态会也会做相应的更新,利用这一点就能够实现父子组件数据的“双向绑定”,虽然这样实现能够节省代码,但会牺牲数据流向的简洁性,令人难以理解,最好不要这样去做。想要实现父子组件的数据“双向绑定”,可以使用 v-model 或 .sync。
-
组件中不能使用同名的数组,不然会被浏览器认为是同数组
v-model 是用来在表单控件或者组件上创建双向绑定的,他的本质是 v-bind 和 v-on 的语法糖,在一个组件上使用 v-model,默认会为组件绑定名为 value 的 prop 和名为 input 的事件。 这样就不需要手动在组件上绑定监听当前实例上的自定义事件,会使代码更简洁。
.sync修饰符 在功能上和 v-model 相似 但是.sync更加的灵活 可以给多个prop使用 而v-model在一个组件中只能有一个
<text-document v-bind:title.sync="doc.title"></text-document>
这样,在子组件中,就可以通过下面代码来实现对这个 prop 重新赋值的意图。
this.$emit('update:title', newTitle)
比如
//父组件将age传给子组件并使用.sync修饰符。
<MyFooter :age.sync="age">
</MyFooter>
//子组件触发事件
mounted () {
console.log(this.$emit('update:age',1234567));
}
子组件触发了父组件的修改函数使父组件的age修改成了1234567
事件名称被换成了update:age
update:是被固定的也就是vue为我们约定好的名称部分
age是我们要修改的状态的名称,是我们手动配置的,与传入的状态名字对应起来
子传父
要先在父组件中引入子组件
在子组件中使用$emit来发送事件 有两个参数,参数名和参数值
在父组件的子标签中自定义一个事件绑定 子组件传输过来的参数名
非父子关系传值
当不是父子关系的组件可以使用eventbus 来进行组件传值
enentBus可以实现任意两个组件之间的通信。在需要使用组件传值的两个组件中都引入相同的新vue实例,在需要发送的组件中使用$emit方法来发送事件 有两个参数 分别是参数名和参数
在需要接收的组件中使用$on(参数名,参数=》{})来接收
直接在页面引入bus,经过webpack打包后可能会出现bus局部作用域的情况,就是说引用的不算是同一个bus,最后不能正常通信
可以将Bus直接注入到Vue根对象中来解决这个问题
import Vue from 'vue'
const Bus = new Vue()
var app= new Vue({
el:'#app',
data:{
Bus
}})
ps: 在子组件中通过this.$root.Bus.$on(),this.$root.Bus.$emit()来调用
Vuex
多个组件传参的时候可以使用vuex
vuex它是个基于vue的状态管理库
大型项目中 可以使用commit来传输数据
用state来获取数据
使用mutation来修改要储存中的值
为了方便使用还要引入四个map辅助函数把vuex中的数据和方法映射到vue组件中
但是小型的项目组件通信用vuex实在是太繁琐了 所以小型的项目可以使用简单的store
和vuex一样 stores中的state 的改变都由 store 内部的 action 来触发,并且能够通过log 保留触发的痕迹
//store.js
var store = {
debug: true,
state: {
author: 'yushihu!'
},
setAuthorAction (newValue) {
if (this.debug) console.log('setAuthorAction triggered with', newValue)
this.state.author = newValue
},
deleteAuthorAction () {
if (this.debug) console.log('deleteAuthorAction triggered')
this.state.author = ''
}
}
事件总线原理 看看就好
$on
$on
来收集所有事件依赖的,会将传入的参数event
和fn
作为key
和value
的形式传到vm._events
这个事件集合里 比如vm._events[event]=[fn]
$emit
$emit
来触发事件 它会根据传入的event
在vm_event
中找到对应的事件并且执行invokeWithErrorHandling(cbs[i], vm, args, vm, info)
的
通过invokeWithErrorHandling
方法可以知道,它是通过handler.apply(context, args)
和handler.call(context)
的形式执行对应的方法
根据原理 自定义实现一个Bus
// Bus: 事件派发、监听和回调
class Bus {
constructor() {
this.callbacks = {}
}
// 收集监听的回调函数
$on(name, fn) {
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
// 执行监听的回调函数
$emit(name, args) {
if (this.callbacks[name]) {
this.callbacks[name].forEach(cb => cb(args))
}
}
}
// 在main.js中这样使用
Vue.prototype.$bus = new Bus()