Vue.observable
<body>
<div id="root">
{{message}}
<button @click="change">Change</button>
</div>
<script>
const state = Vue.observable({ message: 'Vue 2.6' })
const mutation = {
setMessage(value) {
state.message = value
}
}
new Vue({
el: '#root',
computed: {
message() {
return state.message
}
},
methods: {
change() {
mutation.setMessage('Vue 3.0')
}
}
})
</script>
</body>
官方解释:
Vue.observable(object) 是vue2.6版本新增的全局API,它可以让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新。也可以作为最小化的跨组件状态存储器,用于简单的场景
在 Vue 2.x 中,被传入的对象会直接被 Vue.observable 改变;在 Vue 3.x 中,则会返回一个可响应的代理,而对源对象直接进行修改仍然是不可响应的。因此,为了向前兼容,官方推荐始终操作使用 Vue.observable 返回的对象,而不是传入源对象。
通俗来说,Vue.observable在简单场景下可以代替vuex
本示例中Vue.observable执行流程:
- 首先initGlobalAPI (vue.js:5406)
- 执行Vue.observable内容
// 2.6 explicit observable API
Vue.observable = function (obj) {
observe(obj);
return obj
};
- vue初始化
- 使用计算属性将state.message渲染到页面
- 点击按钮
- 执行change()
- 执行setMessage(),修改state.message的值
- 使用计算属性将新的state.message值渲染到页面
可以看出Vue.observable实际就是封装了observe:
- 首先判断是否包含__ob__这个属性
- 实例化一个Observer对象:
- 由于本实例中传入的不是数组,进入walk()
- 在walk中遍历key,并使用defineReactive$$1创建响应式对象
Walk through all properties and convert them into getter/setters. This method should only be called when value type is Object.
遍历所有属性并将它们转换为getter/setter。仅当值类型为Object时才应调用此方法。
- 通过property.get进行取值,通过property.set进行赋值
- 接下来调用Object.defineProperty()给对象定义响应式属性(Object.defineProperty是vue.js实现「响应式系统」的关键之一)
- enumerable,属性是否可枚举,默认 false。
- configurable,属性是否可以被修改或者删除,默认 false。
- get,获取属性的方法。(进行依赖收集)(数据劫持)
- set,设置属性的方法。(进行响应式更新)
- dep.notify():通过dep.notify()对观察者watchers进行通知
- 然后state就成全局响应式对象了,
拓展:
- 深入响应式原理 — Vue.js
- vue原理探索–响应式系统
- Vue setter/getter 是何原理?
- 深入解析Vue依赖收集原理
- Vue 核心之数据劫持
- Vue源码解读之Dep,Observer和Watcher
思想来源:观察者模式 vs 发布订阅模式