1.props
(1).父组件 ==> 子组件 通信
//父组件
<template>
<div>
<Student :students="studentList"/>
</div>
</template>
<script>
import Student from './components/Student'
export default {
name:'App',
components:{Student},
data(){
return{
studentList: ['卿卿', '四喜', '快快']
}
},
}
</script>
//子组件
<template>
<div>
<span v-for="(item, index) in students" :key="index">{{item}}</span>
</div>
</template>
<script>
export default{
name:'Student',
props: ['students']
}
</script>
(2).子组件 ==> 父组件 通信(要求父先给子一个函数将子组件需要通信的东西作为函数的参数传递过去)
//父组件
<template>
<div>
<!--通过父组件传给子组件传递函数类型的props实现:子给父传递数据-->
//<Student : 子组件发送数据时调用的方法名=" 父组件接收数据的方法名 "></Student>
<Student :getStudentName="getStudentName"/>
</div>
</template>
<script>
// 引入School组件
import Student from './components/Student'
export default {
name:'App',
components:{Student},
methods:{
getStudentName(name){
//从子组件接收到传递过来的参数
console.log('School接收到了学生名',name)
}
}
}
</script>
//子组件
<template>
<div>
<button @click="sendStudentName">把学生名给School</button>
</div>
</template>
<script>
export default{
name:'Student',
data(){
return{
name:'卿卿'
}
},
props: ['getStudentName'],
methods:{
//发送学生名给父组件
sendStudentName(){
//调用从父组件中props过来的getSchoolName方法,将学校名称通过参数形式传过去
this.getStudentName(this.name)
}
}
}
</script>
注:
-
v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
-
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。(容易出问题,比如即使在没有提交更改时接收数据方更改原数据也会马上更改)
2.组件自定义事件
适用于:子组件 ===> 父组件
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。(感觉和props传递函数很像...)
(1)绑定自定义事件:
第一种方式,在父组件中:
<Demo @abc="test"/> 或 <Demo v-on:abc="test"/>
第二种方式,在父组件中:
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('abc',this.test)//通过this.$refs.xxx.$on('abc',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
}
(2)触发自定义事件:在子组件中通过 this.$emit('事件名',数据) 触发事件
sendStudentName(){
// 触发Student组件实例身上的abc事件
this.$emit('abc', this.name) //$emit为触发
},
- 若想让自定义事件只能触发一次,绑定事件时可以使用
once
修饰符或$once
方法。 - 解绑自定义事件
this.$off('abc')
- 组件上也可以绑定原生DOM事件,需要使用
native
修饰符。
3.全局事件总线
适用于任意组件间通信。
(1)安装全局事件总线:
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})
(2)使用事件总线:
接收数据:A组件接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){
demo(data){......}
}
......
mounted() {
this.$bus.$on('xxxx',this.demo)
}
提供数据:
this.$bus.$emit('xxxx',数据)
-
最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。
4.消息订阅与发布
适用于任意组件间通信(和全局事件总线很像...)。
(1)安装pubsub:npm i pubsub-js
(2)引入: import pubsub from 'pubsub-js'
(3)接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods(){
demo(data){......}
}
......
mounted() {
this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}
(4)提供数据:pubsub.publish('xxx',数据)
(5)最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)
去取消订阅。
5.插槽
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
分类:默认插槽、具名插槽、作用域插槽
使用方式:
(1)默认插槽:子组件中的提供给父组件使用的一个占位符,用<slot></slot>
表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>
标签。
父组件中:
<Category>
<div>html结构1</div>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot>插槽默认内容...</slot>
</div>
</template>
(2)具名插槽:具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。
父组件中:
<Category>
<template slot="center">
<div>html结构1</div>
</template>
<template v-slot:footer>
<div>html结构2</div>
</template>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
</div>
</template>
(3)作用域插槽:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
父组件中:
<Category>
<template scope="scopeData">
<!-- 生成的是ul列表 -->
<ul>
<li v-for="g in scopeData.games" :key="g">{{g}}</li>
</ul>
</template>
</Category>
<Category>
<template slot-scope="scopeData">
<!-- 生成的是h4标题 -->
<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
</template>
</Category>
子组件中:
<template>
<div>
<slot :games="games"></slot>
</div>
</template>
<script>
export default {
name:'Category',
props:['title'],
//数据在子组件自身
data() {
return {
games:['红色警戒','穿越火线','劲舞团','超级玛丽']
}
},
}
</script>
6.Vuex
在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
多组件需要共享数据时使用vuex
- State:保存所有组件的共享状态
--> 语法糖:mapState-用于帮助我们映射state
中的数据为计算属性
- Getters:类似状态值的计算属性
--> 语法糖:mapGetters-用于帮助我们映射getters
中的数据为计算属性
- Mutations:修改 State中状态值的唯一方法,里面包含状态变化监听器和记录器
--> 语法糖:mapMutations-用于帮助我们生成与mutations
对话的方法,即:包含$store.commit(xxx)
的函数
- Actions:用于异步处理 State中状态值,异步函数结束后调用Mutations
--> 语法糖:mapActions-用于帮助我们生成与actions
对话的方法,即:包含$store.dispatch(xxx)
的函数
- Modules:当一个 State 对象比较庞大时,可以将 State 分割成多个Modules 模块。
切割moudules后,使用map方法需要两个参数:...mapState("模块名", 传入数据-数组或对象)