组件之间的通讯简述:
父子组件的关系可以总结为 props 向下传递,事件event向上传递
祖先组件和后代组件(跨多代)的数据传递,可以使用provide和inject来实现
跨组件或者兄弟组件之间的通信,可以通过eventBus或者vuex等方式来实现
- 页面级组件传值
- 通过路由带参数进行传值
- 通过设置
sessionStorage
缓存的形式进行传递
- 父子组件传值
- 父传子
props
,子传父$emit
.sync
v-model
-
$parent
和$children
- 父传子
- 后代组件传值
provide / inject
-
$attrs
和$listeners
- 跨组件或者兄弟组件之间传值
- 小项目少页面用
eventBus
- 大项目多页面使用
vuex
- 小项目少页面用
页面级组件传值
1. 通过路由带参数进行传值
//两个组件 A和B,A组件通过query把orderId传递给B组件(触发事件可以是点击事件、钩子函数等)
this.$router.push({ path: '/f4', query: { orderId: 123 } }) //跳转到f4
//在B组件中获取A组件传递过来的参数
this.$route.query.orderId
<router-link to="/f4?orderId=123">router-link 进入Father4</router-link>
<router-view></router-view>
2. 通过设置 Session Storage缓存的形式进行传递
//两个组件A和B,在A组件中设置缓存orderData
const orderData = { 'orderId': 123, 'price': 88 }
sessionStorage.setItem('orderInfo', JSON.stringify(orderData))
//B组件就可以获取在A中设置的缓存了
const orderInfo = JSON.parse(sessionStorage.getItem('orderInfo'))
父子组件传值
1. 父传子props
,子传父$emit
.sync
//父组件
<template>
<div>
父组件:{{title}}
<childDom :title.sync="title"></childDom>
</div>
</template>
<script>
import childDom from '../components/Father3-Child'
export default {
data(){
return {
title:'简单我的简单'
}
},
components:{childDom}
}
</script>
//子组件
<template>
<div>
<div>子组件:{{title}}</div>
<button @click="$emit('update:title','哈哈哈')">点我更新父组件的数据</button>
</div>
</template>
<script>
export default {
props:['title'],
}
</script>
v-model
//父组件
<template>
<div>
<aa class="abc" v-model="test" ></aa>
{{'外面的值:' + test}}
<button @click="fn">外面改变里面</button>
</div>
</template>
<script>
import aa from './aa'
export default {
data () {
return {
test: ''
}
},
methods: {
fn () {
this.test += 1
}
},
components:{
aa
}
}
</script>
//子组件
<template>
<div>
{{'里面的值:'+ msg}}
<button @click="fn2">里面改变外面</button>
</div>
</template>
<script>
export default {
/**
* 使用model, 这里有2个属性
* prop属性说,父组件的v-model的值就是msg
* event说,我emit ‘cc’ 的时候,父组件v-model的值就是参数的值
*/
model: {
prop: 'msg',
event: 'cc'
},
props: {
msg: ''
},
methods: {
fn2 () {
this.$emit('cc', this.msg+2)
}
}
}
</script>
2. $parent
和$children
在组件内部可以直接通过子组件
$parent
对父组件进行操作,父组件通过$children
对子组件进行操作.
//父组件
<template>
<div>
<p>fatherMessage:{{fatherMessage}}</p>
<button @click="changeChildValue">改变子组件的数据childMessage</button >
<child></child>
<child2></child2>
</div>
</template>
<script>
import child from '../components/Father4-Child'
import child2 from '../components/Father4-Child2'
export default {
data(){
return {
fatherMessage:'hello'
}
},
components:{child,child2},
methods:{
changeChildValue(){
this.$children[0].childMessage = 'hello';
this.$children[1].childMessage = 'hello2';
}
}
}
</script>
//子组件1
<template>
<div class="container">
child
<input type="text" v-model="childMessage" @input="changeValue">
</div>
</template>
<script>
export default {
// props:{
// value:String, //v-model会自动传递一个字段为value的prop属性
// },
data(){
return {
childMessage:this.value
}
},
methods:{
changeValue(){
this.$parent.fatherMessage = this.childMessage;//通过如此调用可以改变父组件的值
}
},
}
</script>
//子组件2
<template>
<div class="container">
child2
<input type="text" v-model="childMessage" @input="changeValue">
</div>
</template>
<script>
export default {
// props:{
// value:String, //v-model会自动传递一个字段为value的prop属性
// },
data(){
return {
childMessage:this.value
}
},
methods:{
changeValue(){
this.$parent.fatherMessage = this.childMessage;//通过如此调用可以改变父组件的值
}
},
}
</script>
后代组件传值(父组件与子、孙子、曾孙子组件传值)
1. provide / inject
provide / inject 可以以一个祖先组件向所有子孙后代注入依赖。
简单的来说就是在父组件中通过provide来提供变量,然后在后代组件中通过inject来注入变量,不仅限于prop的父子组件数据交互,只要在上一层级的声明的provide,那么下一层级无论多深都能够通过inject来访问到provide的数据
//父组件
<template>
<div>
<son></son>
</div>
</template>
<script>
import son from '../components/son';
export default {
provide: {
foo: 'bar'
},
components:{son}
}
</script>
//子组件
<template>
<div>
我是子组件{{foo}}
<grandson></grandson>
</div>
</template>
<script>
import grandson from '../components/grandson'
export default {
inject: ['foo'],
components:{grandson}
}
</script>
//孙子组件
<template>
<div>
我是孙子组件{{foo}}
</div>
</template>
<script>
export default {
inject: ['foo'],
}
</script>
2. $attrs
和$listeners
通过
$attrs
属性将父组件的数据(不作为prop
被识别的数据)传递给子组件、孙子组件、曾孙子组件等后代组件
$listeners
属性是一个对象,里面包含了作用在这个组件上的所有监听器,我们在子组件上绑定v-on=”$listeners”
, 就可以在父组件中监听孙子组件、曾孙子组件触发的事件,就能把孙子组件、曾孙子组件等后代组件发出的数据,传递给父组件。
//父组件
<template>
<div>
{{coo}}
<child-dom
:foo="foo"
:coo="coo"
@upRocket="reciveRocket">
</child-dom>
</div>
</template>
<script>
import childDom from "../components/Father2-Child";
export default {
name:'demoNo',
data() {
return {
foo:"Hello, world",
coo:"Hello,rui"
}
},
components:{childDom},
methods:{
reciveRocket(ev){
this.coo = ev;//改变数据
console.log(this.coo)
}
}
}
</script>
//子组件
<template>
<div>
<p>foo:{{foo}}</p>
<p>attrs:{{$attrs}}</p>
<childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
</div>
</template>
<script>
import childDomChild from '../components/Father2-Child-Child';
export default {
props:["foo"],
components:{childDomChild}
}
</script>
//孙子组件
<template>
<div>
<p>coo:{{$attrs.coo}}</p>
<button @click="startUpRocket">我要发射火箭</button>
</div>
</template>
<script>
export default {
methods:{
startUpRocket(){
this.$emit("upRocket",'简单我的简单');
}
}
}
</script>
跨组件或者兄弟组件之间传值
小项目少页面用eventBus
总结:
EventBus 又称为事件总线,在Vue中可以使用 EventBus 来作为沟通桥梁,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所有组件都可以上下平行地通知其他组件
在需要传值的组件中用eventBus.$emit
触发一个自定义事件,并传递参数
在需要接收数据的组件中用eventBus.$on
监听自定义事件,并在回调函数中处理传递过来的参数
EventBus原理是发布订阅
eventBus容易导致命名冲突,所以大项目要用vuex
<template>
<div>
<brother1></brother1>
<brother2></brother2>
</div>
</template>
<script>
import {eventBus} from '../components/eventBus.js';
let brother1 = {
template:'<div>{{color}} <button @click="fnEmit2">变红</button></div>',
data(){
return {color:'红色',old:'红色'}
},
created(){
eventBus.$on('changeColor1',(val)=>{ // 绑定自定义事件
this.color = val;
})
},
methods:{
fnEmit2(){
eventBus.$emit('changeColor2',this.old) // 触发自定义事件
}
}
}
let brother2 = {
template:'<div>{{color}} <button @click="fnEmit1">变绿</button></div>',
data(){
return {color:'绿色',old:'绿色'}
},
created(){
eventBus.$on('changeColor2',(val)=>{
this.color = val;
})
},
methods:{
fnEmit1(){
eventBus.$emit('changeColor1',this.old)
}
}
}
export default {
components:{
brother1,brother2
}
}
</script>
//eventBus.js
import Vue from 'vue';
export const eventBus = new Vue();
大项目多页面使用 vuex
vuex主要借鉴了flux redux,vuex只能在vue中使用(单独为vue开发的)
vuex为大型项目而生,主要是(状态)管理,状态指的是数据,将数据统一管理
每一个vuex应用的核心是store,store是一个容器
不能直接改变store中的状态,通过commit一个mutation来更改状态
//main.js
import Vue from 'vue';
import App from './App.vue';
import store from './store'
//计数器
new Vue({
el:'#app',
...App,
store, //store被注册到了实例上 所有组件都会有this.$store这个属性
})
//store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import logger from 'vuex/dist/logger'; //logger是一个日志插件
Vue.use(Vuex);
//容器是唯一的 不可以更改 所以用const比较好
const state={count:0};
const getters={ //相当于computed
val:(state)=>state.count%2 ? '奇数' : '偶数'
};
import mutations from './mutations';
export default new Vuex.Store({
state,
mutations,
getters,
plugins:[logger()],
strict:true //严格模式 只能通过mutation(管理员)来更改状态,mutation不支持异步
})
//App.vue
<template>
<div>
<Counter></Counter>
</div>
</template>
<script>
import Counter from './components/Counter'
export default {
data(){
return {
msg:'hello',
}
},
components:{
Counter
}
}
</script>
//Counter.vue
<template>
<div>
计数器:<button @click="reduce">-</button>
<br>
当前:{{$store.state.count}}<br>
计数器:<button @click="add">+</button><br>
{{$store.getters.val}}
</div>
</template>
<script>
import * as Types from '../store/mutations-types';
export default {
data(){
return {
msg:'hello',
}
},
methods:{
add(){
this.$store.commit(Types.INCREMENT,2); //提交add的mutation, 2是载荷payload
},
reduce(){
this.$store.commit(Types.DECREMENT,1);
}
}
}
</script>
// store/mutations.js
import * as Types from './mutations-types';
const mutations={
[Types.INCREMENT](state,count){ //state是自动放入的,默认指的就是当前的state
state.count+=count;
},
[Types.DECREMENT](state,count){
state.count-=count;
}
};
export default mutations;
// store/mutations-types.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';