组件间通信第一种方式:使用标签传递数据,props声明接收属性
组件间通信第二种方式:vue自定义事件,绑定事件监听和触发事件
组件间通信第三种方式:消息订阅和发布,使用pubsubjs库
使用ubsub通信的好处就是,两个组件间的位置没有任何要求
有三层组件,App–List–Item
在Item中有删除选中行的功能,在App中订阅消息,在Item中发布消息
App.vue
<template>
<div class="todo-container">
<div class="todo-wrap">
<!--<TodoHeader @addTodo="addTodo"/>-->
<TodoHeader ref="header"/>
<TodoList :todos="todos"/>
<TodoFooter :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAll="selectAll"/>
</div>
</div>
</template>
<!--
绑定事件监听----订阅消息
触发事件----发布消息
-->
<script>
// 先引入pubsub-js
import PubSub from 'pubsub-js'
import TodoHeader from './components/TodoHeader.vue'
import TodoList from './components/TodoList.vue'
import TodoFooter from './components/TodoFooter.vue'
import storageUtils from './utils/storageUtils'
export default {
data () {
return {
// todos: JSON.parse(localStorage.getItem('todos_key') || '[]') // 读取localStorage保存的数据
todos: storageUtils.readTodos()
}
},
mounted () { //执行异步代码
// 给<TodoHeader/>绑定自定义事件(addTodo)监听
// this.$on('addTodo', this.addTodo) 绑定监听的目标不对,这里的this是App组件,而addTodo绑定在TodoHeader上,需要TodoHeader去触发
this.$refs.header.$on('addTodo', this.addTodo)
// 订阅消息(deleteTodo),传递两个参数:订阅的消息名称和处理函数function(msg,data){}
// 删除选择行,需要知道选择行的下标index,msg没有用到,其实msg就是deleteTodo,但是不能省略,省略了function(data){},会默认将data当做msg实参
PubSub.subscribe('deleteTodo', (msg, index) => {
this.deleteTodo(index)
})
},
methods: {
addTodo (todo) {
this.todos.unshift(todo)
},
deleteTodo (index) {
this.todos.splice(index, 1)
},
// 删除所有已完成的
deleteCompleteTodos () {
this.todos = this.todos.filter(todo => !todo.complete)
},
// 全选/全不选
selectAll (isSelectAll) {
this.todos.forEach(todo => {
todo.complete = isSelectAll
})
}
},
watch: {
todos: {
deep: true, // 深度监视
/*handler: function (val) {
// 将数据(json)保存到localStorage
// localStorage.setItem('todos_key', JSON.stringify(val))
storageUtils.saveTodos(val)
}*/
// handler的值应该是一个函数, 且函数应该要有一个形参(接收todos最新的值)
handler: storageUtils.saveTodos,
/*handler: function (todos) {
localStorage.setItem(TODOS_KEY, JSON.stringify(todos))
}*/
}
},
components: {
TodoHeader,
TodoList,
TodoFooter
}
}
</script>
<style>
</style>
Item.vue组件
<template>
<li :style="{background: bgColor}" @mouseenter="handleEnter(true)" @mouseleave="handleEnter(false)">
<label>
<input type="checkbox" v-model="todo.complete"/>
<span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" v-show="isShow" @click="deleteItem">删除</button>
</li>
</template>
<script>
//要发布消息,先引入pubsub-js
import PubSub from 'pubsub-js'
export default {
props: {// 指定属性名和属性值的类型
todo: Object,
index: Number
},
data () {
return {
bgColor: 'white',
isShow: false
}
},
methods: {
handleEnter (isEnter) {
if(isEnter) { // 进入
this.bgColor = '#cccccc'
this.isShow = true
} else { // 离开
this.bgColor = '#ffffff'
this.isShow = false
}
},
deleteItem () {
// this.deleteTodo(this.index)
// 发布消息(deleteTodo),删除选择行,需要传递下标参数,index
PubSub.publish('deleteTodo', this.index)
}
}
}
</script>
<style>
</style>