Vue学习10–父子组件通信
父子组件
是指一个A组件把另外一个B组件引入并使用,把A称为父组件,把B称为子组件。
父组件向子组件传数据
使用标签的属性来传递
原理:props
形式:
父组件里: <子组件名 :属性名=“值”>
子组件里:需要在js里用props属性接收父组件传递过来的属性数据
子组件里每个接收的变量的属性:
type:指定数据类型,(Array、Object、String、Number、Boolean)
若类型不匹配也会报错:[Vue warn]: Invalid prop: type check failed for prop “amount”. Expected 期待类型 with value 9908, got 传的类型 with value “9908”.
required:是一个布尔属性,用于指定是否为必传属性
若没传这个必传参数,报错:[Vue warn]: Missing required prop: “amount” (必传参数xxx没有传递)
default:默认值,当指定的数据类型为Array 或者Object 时,default必须使用工厂函数
若Array 或者Object没用工厂函数则报错:[Vue warn]: Invalid default value for prop “item”: Props with type Object/Array must use a factory function to return the default value.
示例:
这是父组件文件
<template>
<div>
<ul>
<!-- <item-node v-for="item in list" :name="item.name" :amount="item.amount + ''" :key="item.id"/> -->
<item-node v-for="item in list" :name="item.name" :amount="item.amount" :key="item.id"/>
<hr/>
<!-- <item-node v-for="item in list" :name="item.name" :key="item.id"/> -->
<!-- 如果一个属性没有添加v-bind:指令,表示这个属性的值为字符串 -->
<!-- [Vue warn]: Invalid prop: type check failed for prop "item". Expected Object, got String with value "". -->
<!-- <item-node v-for="item in list" :name="item.name" :amount="item.amount" item="" :key="item.id"/> -->
</ul>
</div>
</template>
<script>
import ItemNode from './Item'
export default {
components: {
ItemNode
},
data() {
return {
list: Array.from(Array(10), (_, i) => ({id: '张三0' + i, name: '张三0' + i, amount: Math.ceil(Math.random() * 5000 + 7000)}) )
}
}
}
</script>
这是子组件文件
<template>
<li>
<span>{{name}}</span>
的工资是:
<i>{{amount}}</i>
<!-- <i :class="[{'normal': }]"></i> -->
</li>
</template>
<script>
export default {
// 使用props接收父组件传递过来的属性数据
props: {
name: '',
amount: {
// 可以定义数据类型
type: Number,
// 使用定义当前变量为必传参数
required: true
},
item: {
type: Object,
// 设置默认值
default: function() {
return { amount: 10000 }
}
}
}
}
</script>
<style scoped>
i {
font-size: 1.6rem;
font-style: normal;
}
i.normal {
color: green;
}
i.low {
color: wheat;
}
i.high {
color: red;
}
</style>
子组件向父组件传数据
它利用事件机制,父组件绑定一个事件,然后子组件在适当的时机触发这个事件,然后把数据通过事件触发传递出去;
原理:$emit
$emit方法接口解析:
emit 触发、发送一个事件 $emit(event: string, …args: any[])
event: string 事件名字
…args: any[]** **传递多个参数 ( any[]定义为一个数组,它的每一个数据项为任意数据类型 => [‘fds’, 1, true, {}, []] )
js的事件只能触发原生的dom 事件,可以添加一个修饰符来指定事件触发的机制 .native
事件的修饰符除了native之外,.stop 阻止冒泡,.prevent 阻止默认事件,.once 只触发一次
注:所有的修饰符只能使用一个,否则会失效
示例:
这是父组件文件
<template>
<div>
<ul>
<!-- click事件只能触发原生的dom click事件,可以添加一个修饰符来指定事件触发的机制 .native --
<!-- <item-node v-for="item in list" :name="item.name" :amount="item.amount" @click.native.once="testClick" @myClick="testClick" :item="item" :key="item.id"/> -->
<item-node v-for="item in list" :name="item.name" :amount="item.amount" @click.native="testClick" @myClick="testClick" :item="item" :key="item.id"/>
</ul>
</div>
</template>
<script>
import ItemNode from './Item'
export default {
components: {
ItemNode
},
data() {
return {
list: Array.from(Array(10), (_, i) => ({id: '张三0' + i, name: '张三0' + i, amount: Math.ceil(Math.random() * 5000 + 7000)}) )
}
},
methods: {
testClick() {
console.log(arguments)
}
}
}
</script>
这是子组件文件
<template>
<li>
<span>{{name}}</span>
的工资是:
<i>{{amount}}</i>
<i :class="[{'normal': item.amount > 9000 && item.amount < 11000}, {'low': item.amount <= 9000}]" @click.once="clickEvt(item.id)"> -- {{amount}}</i>
</li>
</template>
<script>
export default {
// 使用props接收父组件传递过来的属性数据
props: {
name: '',
// amount: 0
amount: {
type: Number,
required: true
},
item: {
type: Object,
default: function() {
return { amount: 10000 }
}
}
},
methods: {
clickEvt(id) {
// click 自定义事件
// myClick 自定义事件
// 如果使用.native 这个事件就不能触发
this.$emit('click', id, 'fds', 1, true, {}, [])
this.$emit('myClick', id, 'fds', 1, true, {}, [])
}
}
}
</script>
<style scoped>
i {
font-size: 1.6rem;
font-style: normal;
cursor: pointer;
}
i.normal {
color: green;
}
i.low {
color: wheat;
}
i.high {
color: red;
}
</style>
事件捕获有几个阶段?捕获、目标、冒泡三个阶段
数据传值之事件总线
在Vue1.x 版本时候有一个广播对象,可以实现全局的数据传递,在需要传递数据的地方发起一个广播消息,然后在需要使用消息的地方来接消息。
需要先监听,然后在发送
广播机制是基于 事件机制:
以下的 VueInstance 代表Vue实例
触发机制 -> VueInstance.$emit === onclick/onmyclick
监听机制 -> VueInstance.$on === addEventListener
$on方法接口解析:
VueInstance.$on(event :{string | Array}, callback:Function)
监听当前实例上的自定义事件。事件可以由 VueInstance.$emit 触发。
event :事件的名字,String类型的数据或者数组
callback:回调函数 ,会接收所有传入事件触发函数的额外参数(arguments)。
示例:
index.js文件里设置全局监听广播
import Vue from 'vue'
import App from './views'
new Vue({
// 在全局的地方定义一个vue实例对象变量
data() {
return {
eventBus: new Vue()
}
},
render: ce => ce(App),
created() {
// 用全局的vue实例对象来监听一个名字固定的广播,
this.eventBus.$on('importantMsg', function() {
console.log(arguments)
})
}
}).$mount('#app')
自定义Button组件的文件
<template>
<button @click="clickEvt">
{{text}}
</button>
</template>
<script>
export default {
props: {
text: {
type: String,
required: true
}
},
methods: {
clickEvt() {
// 先获取index.js vue实例对象中的eventBus对象,用来发送全局广播
// console.log(this)
this.$root.eventBus.$emit('importantMsg', 'haha', 123)
}
}
}
</script>
这个Button组件不管放在哪个组件或者页面里,都可以发送全局广播
在vue2.x有一个全局 **事件总线 **机制可以实现vue1.x的事件广播机制
事件总线问题:
全局,性能不好,全局事件污染。
必须要先监听。
广播出去的数据不会有缓存,一旦完成事件触发,数据没有接收到,就永远丢失。