日常开发者经常会遇到多层级嵌套组件,并且需要在最里面的子组件触发最外面的父组件事件,这种情况下当然最好的做法其实还是使用Vuex进行管理,如果你的项目使用Vuex进行管理了,后面就没必要看了。Vuex的相关内容请自行百度查阅。
第一种:直接在子组件中通过this.$parent.event
来调用父组件的方法
这种方式可以无限级别的向上找父级,例如:this.$parent.$parent.$parent.$parent.event
,子组件也不需要props
属性接收父组件的方法,但是多层级的时候容易搞乱层级,.$parent
太多了
父组件
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from '@/components/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('fatherMethod');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod();
}
}
};
</script>
第二种:父组件把方法传入子组件中,在子组件里直接调用这个方法
父组件内调用子组件的时候需要显示的传入方法(注意:这里是用的:
传入方法),子组件还需要通过props
接收父组件传来的方法,否则也不可以调用,另外就是多层级的时候需要一层一层的往下传,这时候就比较繁琐
父组件
<template>
<div>
<child :fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '@/components/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('fatherMethod');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
props: {
fatherMethod: {
type: Function,
default: null
}
},
methods: {
childMethod() {
if (this.fatherMethod) {
this.fatherMethod();
}
}
}
};
</script>
第三种:子组件里用$emit
向父组件触发一个事件名(注意:这里是用的@
传入方法),父组件监听这个事件名就行了,子组件不需要通过props
接收父组件传来的方法,否则也不可以调用,这种最好向上传递一层父级,否则也需要层层传递
父组件
<template>
<div>
<child @fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '@/components/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('fatherMethod');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$emit('fatherMethod');
}
}
};
</script>
第四种:使用$emit
和 $on
配合传递事件
如果仅仅是父子一层,传递事件就使用第三种就可以了,如果多层传递或者是兄弟组件,还可以使用$emit
和 $on
配合,其原理就是new 一个vue实例,然后在父子组件引入这个实例,这样在子组件触发的事件就会在父组件监听到了,这就是网上说的eventBus。
新建一个bus.js
import Vue from 'vue';
export default new Vue();
在父子组件分别引入这个bus.js
import eventBus from 'bus';
在子组件触发事件
export default {
methods: {
childMethod() {
eventBus.$emit('fatherMethod');
}
}
};
在父组件监听事件
export default {
mounted() {
//如果出现多次监听,肯定是没有解绑,可以在监听之前解绑,也可以在进入到这个路由或者渲染组件时候解绑一下就好了
eventBus.$off('fatherMethod');
eventBus.$on('fatherMethod');
}
};
当然如果你觉得建一个bus.js
文件多余的话,可以在main.js
里把bus
加到原型上
//vue原型链挂载总线
Vue.prototype.eventBus = new Vue();
加到原型上的好处就是全局都可以使用了
this.eventBus.$emit('fatherMethod');
this.eventBus.$on('fatherMethod');