父子组件通信
1. 使用props和$emit()
父组件 -> 子组件:父组件使用v-bind(冒号是简写)传参,子组件通过props接收
子组件 -> 父组件:子组件使用$emit()向外传递自定义事件,父组件通过v-on(@是简写)监听,可以使用$event接收参数,也可通过定义一个method接收参数
这应该是项目中最常用的方法,不多说了吧。
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<!-- 可以使用$event接收参数 -->
<the-child
:message="message"
@changeMessage="message = $event"
></the-child>
<!-- 也可以通过定义一个methods接收参数 -->
<the-child
:message="message"
@changeMessage="handleMessage"
></the-child>
</div>
</template>
<script>
import TheChild from './TheChild.vue';
export default {
components: {
TheChild
},
data() {
return {
message: '您好,加菲猫'
}
},
methods: {
handleMessage(val) {
this.message = val;
}
}
}
</script>
子组件代码如下:
<template>
<div>
<h1>这是子组件</h1>
<div>{{ message }}</div>
<button @click="handleClick">按钮</button>
</div>
</template>
<script>
export default {
props: ['message'],
methods: {
handleClick() {
this.$emit('handleMessage', '您点击了按钮');
}
}
}
</script>
2. 使用回调函数
父组件 -> 子组件:父组件使用v-bind(冒号是简写)传参,子组件通过props接收
子组件 -> 父组件:父组件通过v-bind将修改参数的方法传入子组件,然后由子组件调用这个方法
个人感觉这个方法并没有实际用处,毕竟这里没有真的在传递参数,不过倒是提供了一个思路,可以通过子组件调用父组件中的方法。
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<!-- 这里子组件接受了两个参数 -->
<the-child
:message="message"
:changeMessageFn="handleMessage"
></the-child>
</div>
</template>
<script>
import TheChild from './TheChild.vue';
export default {
components: {
TheChild
},
data() {
return {
message: '您好,加菲猫'
}
},
methods: {
// 这个方法作为props传入子组件
handleMessage() {
this.message = '您点击了按钮';
}
}
}
</script>
子组件代码如下:
<template>
<div>
<h1>这是子组件</h1>
<div>{{ message }}</div>
<button @click="changeMessageFn">按钮</button>
</div>
</template>
<script>
export default {
props: ['message', 'changeMessageFn']
}
</script>
3. 使用$parent()和$children()
父组件 -> 子组件:父组件通过$children[0],$children[1]去访问子组件实例
子组件 -> 父组件:子组件通过$parent去访问父组件实例
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<button @cilck="handleChildNumber">按钮</button>
<the-child></the-child>
</div>
</template>
<script>
import TheChild from './TheChild.vue';
export default {
components: {
TheChild
},
data() {
return {
message: '您好,加菲猫'
}
},
methods: {
handleChildNumber() {
// 因为一个父组件可能会有很多子组件,所以需要使用下标去访问
this.$children[0].number = 50;
}
}
}
</script>
子组件代码如下:
<template>
<div>
<h1>这是子组件</h1>
<div>{{ number }}</div>
<div>{{ parentMessage }}</div>
</div>
</template>
<script>
export default {
data() {
return {
number: 10
}
},
computed: {
parentMessage() {
return this.$parent.message;
}
}
}
</script>
4. 使用provide + inject
provide/inject 是 Vue 内置的无依赖的组件通信接口,允许一个祖先组件向其所有后代注入一个依赖,不论组件层次有多深,这和 React 中的 Context 特性相似。
provide/inject 主要为高阶插件、组件库提供用例,并不推荐直接应用于应用程序代码中。
父组件 -> 子组件:父组件使用provide提供一个值,子组件使用inject拿到父组件的值
子组件 -> 父组件:应该可以用同样的方法,还没验证过
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<the-child></the-child>
</div>
</template>
<script>
import TheChild from './TheChild.vue';
export default {
components: {
TheChild
},
provide: {
message: '您好,加菲猫'
}
}
</script>
子组件代码如下:
<template>
<div>
<h1>这是子组件</h1>
<div>{{ message}}</div>
</div>
</template>
<script>
export default {
inject: ['message'],
}
</script>
5. 使用$attrs + $listeners
父组件 -> 子组件:父组件中使用v-bind进行传参,可以传递多个参数,子组件通过$attrs接收父组件传过来的参数
子组件 -> 父组件:子组件中使用$listeners获取到父组件中定义的事件监听器,也就是v-on,并执行绑定的事件处理函数
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<the-child
:name="name"
:age="age"
@changeName="changeName"
></the-child>
</div>
</template>
<script>
import TheChild from './TheChild.vue';
export default {
components: {
TheChild
},
data() {
return {
name: '加菲猫',
age: '18'
}
},
methods: {
changeName() {
this.name = '还是加菲猫'
}
}
}
</script>
子组件代码如下:
<template>
<div>
<h1>这是子组件</h1>
<button @click="$listeners.changeName">按钮</button>
<div>姓名:{{ $attrs.name }}</div>
<div>年龄:{{ $attrs.age}}</div>
<!-- $attrs包括了父组件传过来的name和age,还可以继续传给下一级组件 -->
<grand-child v-bind="$attrs"></grand-child>
</div>
</template>
<script>
import GrandChild from './GrandChild.vue'
export default {
components: {
GrandChild
}
}
</script>
6. 使用ref属性
父组件 -> 子组件:父组件使用ref将子组件注册起来,使用this.$refs获取到组件实例,进而访问子组件的属性和方法
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<the-child ref="childComp"></the-child>
<button @click="changeName">按钮</button>
</div>
</template>
<script>
import TheChild from './TheChild.vue';
export default {
methods: {
changeName() {
console.log('点击前', this.$refs.childComp.age);
this.$refs.childComp.changeAge();
console.log('点击后', this.$refs.childComp.age);
}
}
}
</script>
子组件代码如下:
<template>
<div>
<h1>这是子组件</h1>
<div>年龄:{{ age }}</div>
</div>
</template>
<script>
export default {
data() {
return {
age: 20
}
},
methods: {
changeAge() {
this.age = 50;
}
}
}
</script>
兄弟组件通信
1. 使用props + $emit()
子组件传递的参数需要先经过父组件,才能传到另一个子组件。
父组件代码如下:
<template>
<div>
<h1>这是父组件</h1>
<div>name: {{ name }}</div>
<the-child1 :name="name" @handleChange="handleChange"></the-child1>
<the-child2 :name="name"></the-child2>
</div>
</template>
<script>
import TheChild1 from './TheChild1.vue';
import TheChild2 from './TheChild2.vue';
export default {
data() {
return {
name: '加菲猫'
}
},
methods: {
// 接收子组件1传递的参数并给data赋值
handleChange(name) {
this.name = name;
}
}
}
子组件1代码如下:
<template>
<div>
<h1>这是子组件1,参数从这里传到子组件2</h1>
<div>name: {{ name }}</div>
<button @click="handleChange"></button>
</div>
</template>
<script>
export default {
props: ['name'],
methods: {
// 向外传递事件和参数
handleChange() {
this.$emit('handleChange', '还是加菲猫');
}
}
}
</script>
子组件2代码如下:
<template>
<div>
<h1>这是子组件2,这里接收子组件1传递的参数</h1>
<div>name: {{ name }}</div>
</div>
</template>
<script>
export default {
props: ['name']
}
</script>
2. 使用EventBus = new Vue()
这个方法不需要经过父组件,所以就不需要使用v-bind和props。EventBus实际上就是Vue实例。在项目根目录下的main.js文件,创建一个EventBus并向外导出。
import Vue from 'vue';
import App from './App';
export const eventBus = new Vue();
new Vue({
render: h => h(App),
}).$mount('#app');
在子组件1中引入eventBus并$emit()一个事件。因为eventBus是vue实例,所以上面存在$emit()方法。
子组件1代码如下:
<template>
<div>
<h1>这是子组件1,参数从这里传到子组件2</h1>
<div>name: {{ myName }}</div>
<button @click="handleChange"></button>
</div>
</template>
<script>
import { eventBus } from '../main'; // 需要先引入eventBus
export default {
data() {
return {
myName = '加菲猫'
}
}
methods: {
// 向外传递事件和参数
handleChange() {
this.myName = '还是加肥猫';
eventBus.$emit('handleChange', '还是加菲猫');
}
}
}
</script>
子组件2也引入eventBus并监听自定义事件,把监听到的值传给当前组件的data
子组件2代码如下:
<template>
<div>
<h1>这是子组件2,这里接收子组件1传递的参数</h1>
<div>name: {{ myName }}</div>
</div>
</template>
<script>
import { eventBus } from '../main'; // 需要先引入eventBus
export default {
data() {
return {
myName = '加肥猫'
}
},
created() {
eventBus.$on('handleChange', (name) => {
this.myName = name;
})
}
}
</script>
3. 使用Vuex = new Vuex.Store()
创建一个文件夹store,里面定义一个index.js,在里面创建一个Vuex.Store并将这个实例导出。
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
name: '加肥猫'
},
mutations: {
changeName(state) {
state.name = '还是加肥猫';
}
}
})
export default store;
在main.js中导入这个实例,并注入到根Vue实例中。
import Vue from 'vue';
import App from './App';
import store from './store';
new Vue({
render: h => h(App),
store
}).$mount('#app');
子组件中可以通过$store.state.name进行访问
子组件1代码如下
<template>
<div>
<h1>这是子组件1,参数从这里传到子组件2</h1>
<div>name: {{ $store.state.name }}</div>
<button @click="handleChange"></button>
</div>
</template>
<script>
export default {
methods: {
// 执行名为changeName的mutation
handleChange() {
this.$store.commit('changeName');
}
}
}
</script>
子组件2代码如下
<template>
<div>
<h1>这是子组件2,这里接收子组件1传递的参数</h1>
<div>name: {{ $store.state.name }}</div>
</div>
</template>
<script>
export default {
}
</script>