先总结一下我所知的一些组件间传值的方法:
- 使用vuex状态管理
- 使用中央事件总线
- 父传子通信,子组件通过props接收父组件v-bind在子组件上的数据
- 子传父通信,子组件通过emit给父组件传值,父组件通过v-on绑定emit传来的方法接收数据
- 在组件内部可以直接通过子组件$parent对父组件进行操作,父组件通过$children对子组件进行操作
- 父组件通过v-model在子组件上绑定数据,会自动传递一个value的prop属性和一个名为
input
的emit,通过$emit('input',val)
自动修改v-model绑定的值 - $attrs和$listeners。props一般只可以父传子,通过这两个属性,可以父传孙
- 通过成对出现的provide和inject选项。父组件通过
provider
提供变量,不管嵌套的多深的子组件都可以通过inject
注入
1、使用Vuex状态管理
Vuex是Vue全家桶中的一员,它相当于中央仓库,组件可以往里面存储数据也可以从里面读取数据。
1)安装Vuex
npm install vuex --save
2)在src文件夹中新建store目录,再新建index.js文件
3)在main.js中引入并实例化
import store from './store'
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
4)index.js中的代码如下
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//state中写的是要存储的数据的名字和类型
state: {
name: ''
},
//之后会通过这个获取state中的数据
getters: {
getName (state) {
return state.name
}
},
//mutations是同步函数,通过store.commit来调用
mutations: {
setName (state, data) {
state.name = data
}
},
//actions是异步函数,通过store.dispatch来调用
actions: {
setName ({commit}, data) {
commit('setName', data)
}
}
})
5)使用Vuex
组件可以通过以下方式来存储和读取store中的数据
this.$store.getters.getName //组件通过这个代码从store中获取数据
this.$store.dispatch('setName', val) //组件通过这个代码将store中的name修改为val的内容
2、中央事件总线
两个组件非父子时,没有什么关联时要怎么传值呢?这种情况除了使用Vuex之外,还可以使用媒介Bus
1)定义eventBus
Vue.prototype.eventBus = new Vue()
2)使用
在需要传递数据的组件中使用如下代码:
methods:{
changesize(){
this.eventBus.$emit('add', val) //'add'是方法名,val是你要传递的数据
}
}
在需要接收数据的组件中使用如下代码:
created(){
this.eventBus.$on('add',(message)=>{
//'add'对应传递数据的组件中emit设置的方法名,message就是从传递数据的组件传过来的值,就是emit设置的val
console.log(message)
})
}
3、父组件向子组件传值
父组件向子组件传值可以在子组件通过props接收父组件传的值
父组件中的代码:
<template>
<div id="container">
<input type="text" v-model="text" @change="dataChange">
<Child :msg="text"></Child>
</div>
</template>
<script>
import Child from "@/components/Child"
export default {
data() {
return {
text: "父组件的值"
}
},
methods: {
dataChange(data){
this.msg = data
}
},
components: {
Child
}
}
</script>
<style scoped>
</style>
子组件中的代码:
<template>
<div>
{{msg}}
</div>
</template>
<script>
export default {
props:{
msg: String
}
};
</script>
父传子的实现方式就是通过props属性,子组件通过props属性接收从父组件传过来的值,而父组件传值的时候使用 v-bind 将子组件中预留的变量名绑定为data里面的数据即可
4、子组件向父组件传值
子组件中的代码:
<template>
<div id="container">
<input type="text" v-model="msg">
<button @click="sendData">传递到父组件</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: "传递给父组件的值"
}
},
methods: {
sendData() {
this.$emit("getData", this.msg)
}
}
}
</script>
父组件中的代码:
<template>
<div id="container">
<Child @getData="getData"></Child>
<p>{{msg}}</p>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
data() {
return {
msg: "父组件默认值"
};
},
methods: {
getData(data) {
this.msg = data;
}
},
components: {
Child
}
};
</script>
<style scoped>
</style>
子组件中通过$emit来向父组件传值
this.$emit('fun1', value) //fun1是父组件中@绑定事件的名称,value是要传递的数据
<Child @fun1="getData"></Child> //fun1就是子组件中emit第一个设置的参数,getData是父组件中自己定义的方法名称
methods: {
getData(data) { //data就是子组件中emit第二个设置的数据,也就是要传递的数据
this.msg = data; //将传递来的数据赋值给自己组件的data
}
},
5、$parent和$children
能直接能过这两个属性访问对方的data
和直接调用对方的method
用$refs
能起到相同的作用
6、v-model父子组件传值
<input v-model="name"> 等价于 <input :value="name" @input="name=$event.targer.value">
就是通过v-model
绑定的数据,子组件自动默认接收一个字段名为value
的props
属性,父组件自动默认接收一个名为input
的emit
事件。
v-model也可以自定义,自己指定props的名字和event的事件名
<script>
export default {
model: {
prop: 'name',
event: 'changeName'
},
props: ['name'],
methods: {
input(val) {
this.$emit('changeName', val)
}
}
}
</script>
父组件代码
<template>
<div>
<child v-model="name"></child>
{{name}}
</div>
</template>
<script>
data() {
return {
name: ''
}
}
</script>
子组件代码
<template>
<div>
<input v-model="name" @input="input">
</div>
</template>
<script>
data() {
return {
name: ''
}
},
methods: {
input() {
this.$emit('input', this.name)
}
}
</script>
上面这段代码子组件中修改了name
的值,会同步更改父组件中name
的值
7、$attrs和$listeners
如果有一个三层嵌套的组件,通过props只能一层一层的往下传递数据,嵌套层数很多的时候代码会很繁冗,这时候就可以通过这个来实现父传孙通信
但是如果父组件所传的属性中有在子组件 props
中有过声明,那么该属性不会出现在 $attrs
对象中
inheritAttrs为true时会把父组件传给子组件而没有在子组件中声明的props属性写在渲染的标签里
父组件
<child :foo="foo" :coo="coo" @receive="receive"></child>
......
<script>
import child from '......'
export default {
components: {child},
data() {
return {
foo: 'hello world',
coo: 'hello relex'
}
},
methods: {
receive() {
}
},
}
</script>
子组件
<p>foo: {{foo}}</p>
<grandson v-bind="$attrs"></grandson>
<script>
import grandson from '.....'
export default {
props: ['foo'],
inheritAttrs: false
}
</script>
孙组件
<p @click="send">coo: {{coo}}</p>
<script>
export default {
props: ['coo'],
inheritAttrs: false,
methods: {
send() {
this.$emit('receive')
}
}
}
</script>
8、provider和inject
成对出现的provider
和inject
属性,实现父组件向下传递数据。
父组件通过provider
提供数据,不管嵌套多深的子组件都能通过inject
注入数据
父组件
<script>
export default {
provider: {
parentData: '父组件的数据'
}
}
</script>
子组件
<div>{{parentData}}</div>
export default {
inject: ['parentData']
}