万金油:vue中央事件总线的使用
vue中央事件总线这种方法适用于任何情况的父子组件通信,同级别组件通信,相当于组件通信间的万金油。但是碰到多人合作时,代码的维护性较低,代码可读性低(这个缺点可以忽略)。
在vue-cli中使用 集中式事件管理机制:
第一步:在 src/main.js新建一个$bus对象,其实他是一个全新的Vue实例
// main.js
let $bus = new Vue()
Vue.prototype.$bus = $bus
示例:index.vue为父组件,两个子组件 header.vue、footer.vue。
在mounted生命周期里通过this.$bus.$on()监听。
在destroyed生命周期里面通过this.$bus.$off()解除绑定。一定要解除绑定事件!!!
//父组件:index.vue:
<template>
<div class="indexPageWrap">
<header></header>
<footer></footer>
</div>
</template>
<script type="text/javascript">
import header from './header.vue';
import footer from './footer.vue';
export default{
data () {
return {
index:0
}
},
mounted () {
this.$bus.$on('fromHeader', (message) => {
this.alreadyCalling(message)
});
this.$bus.$on('fromFooter',this.indexFromFooter);
},
//注意:在组件销毁时,一定要解除绑定事件:
destroyed(){
this.$bus.$off('fromHeader');
this.$bus.$off('fromFooter');
},
components : {
header
},
methods : {
alreadyCalling(vlaue){
console.log('from header');
console.log(value)
},
indexFromFooter(){
console.log('from footer')
}
}
}
</script>
<style type="text/css">
</style>
子组件 header.vue
通过this.$bus.$emit()传递数据
//子组件 header.vue
<template>
<div class="headerPageWrap">
<div @click="headerEmit">Emit<div>
</div>
</template>
<script type="text/javascript">
export default{
data () {
return {
index:0
}
},
mounted () {
this.$bus.$on('headerTofooter',this.headerFromFoot)
},
components : {
},
methods : {
headerEmit(){
this.$bus.$emit('fromHeader',{value:"123"}); //可以传递数据
},
headerFromFoot(){
console.log('from footer');
}
}
}
</script>
<style type="text/css">
</style>
//子组件 footer.vue
<template>
<div class="footerPageWrap">
<div @click="footerEmit">Emit<div>
<div @click="footerEmitToHeader">Emit<div>
</div>
</template>
<script type="text/javascript">
export default{
data () {
return {
index:0
}
},
mounted () {
},
components : {
},
methods : {
footerEmit(){
this.$bus.$emit('fromFooter'); //不传递数据
},
footerEmitToHeader(){
this.$bus.$emit('headerTofooter'); //不传递数据
}
}
}
</script>
<style type="text/css">
</style>
props:最基础的父子组件间传递数据
可以分为 静态传递 或者 使用 v-bind动态传递:例如:
给 prop 传入一个静态的值:
<blog-post title="My journey with Vue"></blog-post>
prop 可以通过 v-bind 动态赋值,例如:
<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
在上述两个示例中,我们传入的值都是字符串类型的,但实际上任何类型(Number,Array,String,Object,对象的所有属性)的值都可以传给一个 prop。
子组件接受:
export default {
props : ["title"]
}
//或者
export default {
props : {
title:{
type:string,
default:""
}
}
}
prop 的验证方式:
export default {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
}
}
}
子组件向父组件传值(通过事件形式)
接下来我们通过一个例子,说明子组件如何向父组件传递值:
// 子组件
<template>
<header>
<h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件
</header>
</template>
<script>
export default {
name: 'app-header',
data() {
return {
title:"Vue.js Demo"
}
},
methods:{
changeTitle() {
this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”
}
}
}
</script>
// 父组件
<template>
<div id="app">
<app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致
// updateTitle($event)接受传递过来的文字
<h2>{{title}}</h2>
</div>
</template>
<script>
import Header from "./components/Header"
export default {
name: 'App',
data(){
return{
title:"传递的是一个值"
}
},
methods:{
updateTitle(e){ //声明这个函数
this.title = e;
}
},
components:{
"app-header":Header,
}
}
</script>
或者
// 父组件
<template>
<div>
<app-header @titleChanged="fatherMethod"></app-header>
<h2>{{title}}</h2>
</div>
</template>
<script>
import Header from "./components/Header"
export default {
components:{
"app-header":Header,
},
data(){
return{
title:"传递的是一个值"
}
},
methods: {
fatherMethod(str) {
console.log(str);
}
}
};
</script>
$refs属性:
// 子组件
<template>
<div>
child
</div>
</template>
<script>
export default {
name: "child",
props: "someprops",
methods: {
parentHandleclick(e) {
console.log(e)
}
}
}
</script>
// 父组件
<template>
<div>
<button @click="clickParent">点击</button>
<child ref="mychild"></child>
</div>
</template>
<script>
import Child from './child';
export default {
name: "parent",
components: {
child: Child
},
methods: {
clickParent() {
this.$refs.mychild.parentHandleclick("嘿嘿嘿");
}
}
}
</script>
vue子组件调用父组件的方法
$parent
// 父组件
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from './child';
export default {
components: {
child
},
methods: {
fatherMethod(str) {
console.log(str);
}
}
};
</script>
// 子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod('hello');
}
}
};
</script>
开发中常使用vue中央事件总线,props, $emit事件形式, 如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的以及Vuex 。下篇文章介绍Vuex在实战开发项目中的使用