Vue学习(十六)全局事件总线(GlobalEvventBus)

本文介绍了如何在Vue应用中使用全局事件总线(GlobalEventBus)来促进组件间的通信,包括安装、使用方法和销毁步骤,以TodoList为例详细展示了其应用过程。

全局事件总线(GlobalEvventBus)

一种事件间的通讯方式,适用于任意组件间的通讯(非官方api,是使用中总结出来的组合),需要符合以下两个要求,才能算是全局事件总线

  1. 确保所有组件都能看到
  2. 可以调用$on$off等方法

安装全局事件总线

new Vue({
    ......
    beforeCreate() {
        Vue.prototype.$bus = this
    },
    ......
})

使用全局事件总线

  1. 接收数据:A组件想要接收数据,则在A组件中给$bus绑定自定义事件,事件的回调在A组件自身
methods() {
    functionName(data) {......},
    mounted() {
        this.$bus.$on('自定义事件名称', this.functionName)
    },
    beforeDestroy() {
        this.$bus.$off('自定义事件名称');
    }
}
  1. 提供数据:B组件想要给A组件提供数据,则在B组件中调用this.$bus.$emit("自定义事件名称", 数据)

销毁

在beforeDestroy钩子中,使用$off解绑当前自定义事件

main.js

// 引入Vue
import Vue from "vue";
// 引入App组件
import App from "./App"


// 关闭生产提示
Vue.config.productionTip = false

// 创建vm
new Vue({
    render: h => h(App),
    beforeCreate() {
        // 安装全局组件
        Vue.prototype.$bus = this
    },
}).$mount("#app");

App组件

<template>
  <div class="app">
    <h1>{{msg}}</h1>
    <School />
    <Student />
  </div>
</template>

<script>
    // 引入School组件
    import School from './components/School.vue'
    import Student from './components/Student.vue'
    
    export default {
        name: "App",
        // 注册组件
        components: {Student, School},
        data() {
          return {
            msg: "你好啊!",
            studentName: ''
          }
        },
    }
</script>

<style>
  .app {
    background-color: gray;
    padding: 5px;
  }
</style>

School组件

<template>
  <div class="school">
    <h2>学校名称:{{name}}</h2>
    <h2>地址:{{address}}</h2>
  </div>
</template>

<script>
    export default {
        name: "School",
        data() {
            return {
                name: "尚硅谷",
                address: "北京·昌平"
            }
        },
        mounted() {
        // 绑定自定义事件
          this.$bus.$on("hello", (data) => {
            console.log("我是School组件,收到了数据", data)
          })
        },
        beforeDestroy() {
        // 解绑自定义事件
          this.$bus.$off("hello");
        },
    }
</script>

<style scoped>
  .school {
    background-color: skyblue;
    padding: 5px;
  }
</style>

Student组件

<template>
  <div class="student">
    <h2>姓名:{{name}}</h2>
    <h2>性别:{{sex}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="sendStudentName">把学生名给School组件</button>
  </div>
</template>

<script>
    export default {
        name: "Student",
        data() {
            return {
                name: "张三",
                sex: "男",
                age: 18
            }
        },
        methods: {
          sendStudentName() {
            this.$bus.$emit("hello", this.name);
          }
        },
    }
</script>

<style scoped>
  .student {
    background-color: orange;
    padding: 5px;
    margin-top: 30px;
  }
</style>

TodoList 全局事件总线

修改App组件MyItem组件的通讯
main.is安装事假总线

// 引入Vue
import Vue from "vue";
// 引入App组件
import App from "./App"


// 关闭生产提示
Vue.config.productionTip = false

// 创建vm
new Vue({
    render: h => h(App),
    beforeCreate() {
        // 安装全局事件总线
        Vue.prototype.$bus = this
    },
    mounted() {
        /* setTimeout(() => {
            this.$destroy();
        }, 3000); */
    },
}).$mount("#app");

App组件使用数据

<template>
    <div id="root">
		<div class="todo-container">
			<div class="todo-wrap">
                <MyHeader @addTodo="addTodo"/>
				
                <MyList 
					:todoList="todoList" 
				/>
                <MyFooter 
					:todoList="todoList" 
					@checkAllTodo="checkAllTodo" 
					@deleteAllDoneTodo="deleteAllDoneTodo" 
				/>

			</div>
		</div>
	</div>
</template>

<script>

    import MyHeader from './components/MyHeader'
    import MyList from './components/MyList'
    import MyFooter from './components/MyFooter'

    export default {
        name: "App",
        // 注册组件
        // components: [MyHeader/* , MyList, MyFooter */]
        components: {MyHeader, MyList, MyFooter},
		data() {
			return {
				todoList: JSON.parse(localStorage.getItem("todoList")) || []
				/* [
					{id: '00001', title: "吃饭", done: true},
					{id: '00002', title: "打游戏", done: false},
					{id: '00003', title: "学习", done: false},
				] */
			}
		},
		methods: {
			addTodo(todoObj) {
				this.todoList.unshift(todoObj);
			},
			checkTodo(todoId) {
				// console.log(todoId)
				this.todoList.forEach((todo) => {
					if (todo.id === todoId) todo.done = !todo.done;
				})
			},
			deleteTodo (todoId) {
				/* this.todoList = this.todoList.filter((todo) => {
					return todo.id !== todoId
				}) */
				this.todoList = this.todoList.filter(todo => todo.id !== todoId)
			},
			checkAllTodo(done) {
				/* this.todoList.forEach((todo) => {
					todo.done = done
				}); */
				this.todoList.forEach(todo => todo.done = done);
			},
			deleteAllDoneTodo() {
				this.todoList = this.todoList.filter(todo => !todo.done);
			}
		},
		watch: {
			/* todoList(value) {
				localStorage.setItem("todoList", JSON.stringify(value))
			} */
			todoList: {
				deep: true,
				handler(value) {
					localStorage.setItem("todoList", JSON.stringify(value))
				},
				
			}
		},
		mounted() {
			this.$bus.$on('checkTodo', this.checkTodo);
			this.$bus.$on('deleteTodo', this.deleteTodo);
		},
		beforeDestroy() {
			this.$bus.$off(['checkTodo', 'deleteTodo']);
		},
    }
</script>

<style>
    /*base*/
	body {
		background: #fff;
	}

	.btn {
		display: inline-block;
		padding: 4px 12px;
		margin-bottom: 0;
		font-size: 14px;
		line-height: 20px;
		text-align: center;
		vertical-align: middle;
		cursor: pointer;
		box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
		border-radius: 4px;
	}

	.btn-danger {
		color: #fff;
		background-color: #da4f49;
		border: 1px solid #bd362f;
	}

	.btn-danger:hover {
		color: #fff;
		background-color: #bd362f;
	}

	.btn:focus {
		outline: none;
	}

	.todo-container {
		width: 600px;
		margin: 0 auto;
	}

	.todo-container .todo-wrap {
		padding: 10px;
		border: 1px solid #ddd;
		border-radius: 5px;
	}
</style>

MyItem传递数据

<template>
    <li>
		<label>
			<!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
			<!-- <input type="checkbox" v-model="todo.done"/> -->
			<!-- <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/> -->
			<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
			<span>{{todo.title}}</span>
		</label>
		<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
	</li>
</template>

<script scoped>
    export default {
        name: "MyItem",
		// 声明接收传入数据
		props: ["todo"],
		data() {
			return {
				
			}
		},
		methods: {
			handleCheck(todoId) {
				// console.log(todoId)
				// this.checkTodo(todoId);
				// this.$bus.$emit('checkTodo', todoId);
			}, 
			handleDelete(todoId) {
				if (confirm("确定删除吗?")) {
					/* console.log(todoId)
					this.deleteTodo(todoId) */
					this.$bus.$emit('deleteTodo', todoId);
				}
			}
		},
    }
</script>

<style>
    /*item*/
	li {
		list-style: none;
		height: 36px;
		line-height: 36px;
		padding: 0 5px;
		border-bottom: 1px solid #ddd;
	}

	li label {
		float: left;
		cursor: pointer;
	}

	li label li input {
		vertical-align: middle;
		margin-right: 6px;
		position: relative;
		top: -1px;
	}

	li button {
		float: right;
		display: none;
		margin-top: 3px;
	}
	li .btn {
		display: none;
	}

	li:before {
		content: initial;
	}

	li:last-child {
		border-bottom: none;
	}

	li:hover {
		background-color: #ddd;
	}

	li:hover button {
		display: block;
	}
</style>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值