如果有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享。采用一个简单的 store 模式:
var store = {
debug: true,
state: {
message: 'Hello!'
},
setMessageAction (newValue) {
if (this.debug) console.log('setMessageAction triggered with', newValue)
this.state.message = newValue
},
clearMessageAction () {
if (this.debug) console.log('clearMessageAction triggered')
this.state.message = ''
}
}
需要注意,所有 store 中 state 的变更,都放置在 store 自身的 action 中去管理。这种集中式状态管理能够被更容易地理解哪种类型的变更将会发生,以及它们是如何被触发。当错误出现时,也会有一个 log 记录 bug 之前发生了什么。
此外,每个实例/组件仍然可以拥有和管理自己的私有状态:
var vmA = new Vue({
data: {
privateState: {},
sharedState: store.state
}
})
var vmB = new Vue({
data: {
privateState: {},
sharedState: store.state
}
})
但是组件不允许直接变更属于 store 实例的 state,而应执行 action 来分发 (dispatch) 事件通知 store 去改变。
props 和 $emit
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。 Prop 的类型可以是这些原生构造函数:String,Number,Boolean,Array,Object,Date,Function,Symbol。 为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:
子组件可以通过调用内建的 $emit 方法并传入事件名称来触发一个事件,并使用第二个参数来传值,父级组件就会接收该事件并更新值。 举例:
$attrs 和 $listeners(2.4.0 新增)
$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。
$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。
$attrs 与 $listeners 是两个「对象」,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners 里存放的是父组件中绑定的非原生事件。
举例:
需要注意 Vue 中组件在接受非 Props 属性时,会把属性渲染到 HTML 的原生标签上。在组件的选项中设置 inheritAttrs: false 即可避免这个问题。
EventBus 事件总线
在 Vue 中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。
初始化
可以通过两种方式创建事件总线:
实质上 EventBus 是一个不具备 DOM 的组件,它具有的仅仅只是它实例方法而已,因此它非常的轻便。
发送事件 $emit
EventBus.$emit( eventName, [ …args] ) $emit 可以触发事件。假设有两个 Vue 页面 A 和 B 需要通信,A 页面在按钮上面绑定了点击事件,发送一则消息,想通知 B 页面。
接收事件 $on
EventBus.$on( event, callback ) $on 监听事件是否被触发,触发时则执行 callback 事件。
上述提到如果 EventBus 使用不当,可能会引起“灾难”。如果反复操作页面,EventBus 在监听的时候可能多次触发事件。 通常在使用时,会在使用 $on 前先调用 $off;并且会在 Vue 页面销毁时,同时移除 EventBus 事件监听。
移除事件 $off
EventBus.$off( event, callback )
全局 EventBus
每次使用 EventBus 时引入 js 文件比较麻烦,可以注册全局的 EventBus。其工作原理就是发布/订阅模式。
在这个特定的总线中,$emit 用于触发事件,$on 用于订阅,$off 用于移除事件监听。
以上笔记参考 Vue事件总线(EventBus)使用详细介绍
provide 和 inject(2.2.0 新增)
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,祖先组件通过 provide 来提供变量,然后在子孙组件中通过 inject 来注入变量,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
v-model
父组件通过 v-model 传递值给子组件时,会自动传递一个 value 的 prop 属性,在子组件中通过 this.$emit("input",val) 自动修改 v-model 绑定的值。原理就是利用 props 和 $emit 进行父子组件通信。
在组件上使用 v-model
自定义事件也可以用于创建支持 v-model 的自定义输入组件。
用于组件时,则是要保证这个组件内的 < input> 必须:
自定义组件的 v-model(2.2.0+ 新增)
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:
这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 < base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。
$parent 和 $children
$parent 可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式。 $children 是当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。
Vuex
Vuex 是专门为 Vue.js 设计的状态管理库,可以帮助我们管理共享状态。 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
核心概念
store 模式
如果有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享。采用一个简单的 store 模式:
需要注意,所有 store 中 state 的变更,都放置在 store 自身的 action 中去管理。这种集中式状态管理能够被更容易地理解哪种类型的变更将会发生,以及它们是如何被触发。当错误出现时,也会有一个 log 记录 bug 之前发生了什么。 此外,每个实例/组件仍然可以拥有和管理自己的私有状态:
但是组件不允许直接变更属于 store 实例的 state,而应执行 action 来分发 (dispatch) 事件通知 store 去改变。