组件间的数据传递
由于组件实例的作用域是单独的。所以就不能在一个组件中直接引用另一个组件中的数据,但是在一个项目中数据的处理往往是很频繁的,并且组件设计初衷就是要配合使用的,通过组件间的关联,来更加高效的处理一些问题。所以,简单的介绍一下组件组合后组件间互相通信的方式
1.父组件 ----> 子组件(prop)
使用 Prop传递数据
组件的孤立作用域,使得子组件的模板内不能直接引用父组件的数据,在这里可以通过prop进行下发,例如:
var child = {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 也可以在模板中使用
template: '< div>{{message}}我是一个子组件!< /div>'
}
export default {
components: {
'children-componment': child
},
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
然后通过向组件传入一个字符串:
< children-componment message="hello" >< /children-componment>
在此处子组件 children-componment显式地用 props 选项声明预期的数据,在使用时又传入字符串,则可将数据下发到子组件中
动态 Prop
往往我们需要子组件来实时的跟踪父组件的数据变化,以做及时的关联处理。此时可以用 v-bind 来动态地将 prop 绑定到父组件的数据。所以每当父组件的数据变化时,该变化也会传导给子组件,可以跟着一起变化:
< template>
< div class="hello">
< h1>{{ msg }}
< input v-model = "parentMsg">
< br>
< children-componment :my-message="parentMsg" >
< /div>
< /template>
var child = {
// 声明 props
props: ['myMessage'],
// 就像 data 一样,prop 也可以在模板中使用
template: '< div> {{myMessage}} 我是一个子组件!< /div>'
}
export default {
components: {
'children-componment': child
},
data () {
return {
msg: 'Welcome to Your Vue.js App',
parentMsg: 'Message from parent'
}
}
}
此时的输入框input是存在于父组件,通过v-model绑定parentMsg,并且将值传递给子组件< children-componment>< /children-componment>,此时的子组件接收的值也是随着父组件的变化而动态改变的。
单向数据流(数据传递过程中需要解决的问题)
Prop 可以实现从父组件到子组件的数据传递,但是同时也要注意,prop是单向绑定的。这也就是意味着当父组件的属性变化时,将传导给子组件,但是当子组件发生改变时却不会反馈给父组件。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。 另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。所以存在着两个容易出错的场景:
- Prop 作为初始值传入后,子组件想把它当作局部数据来用
解决方法 (定义一个局部变量,并用 prop 的值初始化这个局部变量:):
props: ['myMessage'],
// 就像 data 一样,prop 也可以在模板中使用
template: '< div> {{variable}} 我是一个子组件!< /div>',
data: function () {
return {
variable: this.myMessage
}
}
- Prop 作为原始数据传入,由子组件处理成其它数据输出
props: ['param'],
computed: {
//handleParam为处理过可使用的数据
handleParam: function () {
return this.param+5
}
}
!!!注:不能在子组件内部改变 prop
2.子组件 ----> 父组件(绑定自定义事件)
自定义事件
子组件向父组件传递数据使用Vue 的自定义事件系统实现,每个 Vue 实例实现的事件接口:
- 使用 $on(eventName) 监听事件
- 使用 $emit(eventName, optionalPayload) 触发事件
//此处跟着官方文档的例子来梳理一遍
< template>
< div>
< h1>{{total}}< /h1>
//3.组件监听到'increment'事件,并且执行'incrementTotal'方法,改变父组件中的total的值
< children-componment v-on:increment="incrementTotal">+< /children-componment>
< children-componment v-on:increment="incrementTotal">+< /children-componment>
< /div>
< /template>
var child = {
//1.当子组件的按钮按下时执行incrementCounter方法
template: '< button v-on:click="incrementCounter">子组件{{ counter }}< /button>',
data: function () {
return {
counter: 0
}
},
methods: {
2.执行方法,将counter的值加1,并且触发了一个'increment'的事件
incrementCounter: function () {
this.counter += 1
this.$emit('increment')
},
}
}
export default {
data: function () {
return {
total: 0
}
},
methods: {
incrementTotal: function () {
this.total += 1
}
},
components: {
'children-componment': child
},
}
子组件件向父组件传递数据的过程如上注释所标的序号所示:
- 1.当子组件的按钮按下时执行incrementCounter方法
- 2.执行incrementCounter方法,将counter的值加1,并且触发了一个'increment'的事件
- 3.组件监听到'increment'事件,并且执行'incrementTotal'方法,改变父组件中的total的值
如何使用载荷 (payload) 数据,就在刚刚的例子中稍加修改:
var child = {
template: '< button v-on:click="incrementCounter">子组件{{ counter }}< /button>',
data: function () {
return {
counter: 0
}
},
methods: {
incrementCounter: function () {
this.counter += 1
this.$emit('increment',{number:3})
},
}
}
data: function () {
return {
total: 0
}
},
methods: {
incrementTotal: function (payload) {
this.total += payload.number
}
},
components: {
'children-componment': child
},
此时点击一次按钮时,total就是加3,3即为传过来的payload的数据
3.非父子组件的数据传递 (bus总线)
非父子组件之间也需要有数据的传递,此时可以使用空的vue实例bus总线
// 触发组件 A 中的事件
bus.$emit('selected')
// 在组件 B 中监听事件
bus.$on('selected', function () {
// ...
})
简单的数据交互可以使用bus总线的方法,但是在较为复杂的情境下 ,会使用vuex状态管理来实现。这个会在后续的学习中进一步深入了解,并作分享。
下一篇:使用插槽分发内容