参考答案:
Observable
翻译过来我们可以理解成可观察的
我们先来看一下其在Vue
中的定义
Vue.observable
,让一个对象变成响应式数据。Vue
内部会用它来处理data
函数返回的对象
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器
1Vue.observable({ count : 1})
其作用等同于
1new vue({ count : 1})
在 Vue 2.x
中,被传入的对象会直接被 Vue.observable
变更,它和被返回的对象是同一个对象
在 Vue 3.x
中,则会返回一个可响应的代理,而对源对象直接进行变更仍然是不可响应的
在非父子组件通信时,可以使用通常的bus
或者使用vuex
,但是实现的功能不是太复杂,而使用上面两个又有点繁琐。这时,observable
就是一个很好的选择
创建一个js
文件
1// 引入vue 2import Vue from 'vue 3// 创建state对象,使用observable让state对象可响应 4export let state = Vue.observable({ 5 name: '张三', 6 'age': 38 7}) 8// 创建对应的方法 9export let mutations = { 10 changeName(name) { 11 state.name = name 12 }, 13 setAge(age) { 14 state.age = age 15 } 16}
在.vue
文件中直接使用即可
1<template> 2 <div> 3 姓名:{{ name }} 4 年龄:{{ age }} 5 <button @click="changeName('李四')">改变姓名</button> 6 <button @click="setAge(18)">改变年龄</button> 7 </div> 8</template> 9import { state, mutations } from '@/store 10export default { 11 // 在计算属性中拿到值 12 computed: { 13 name() { 14 return state.name 15 }, 16 age() { 17 return state.age 18 } 19 }, 20 // 调用mutations里面的方法,更新数据 21 methods: { 22 changeName: mutations.changeName, 23 setAge: mutations.setAge 24 } 25}
源码位置:src\core\observer\index.js
1export function observe (value: any, asRootData: ?boolean): Observer | void { 2 if (!isObject(value) || value instanceof VNode) { 3 return 4 } 5 let ob: Observer | void 6 // 判断是否存在__ob__响应式属性 7 if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { 8 ob = value.__ob__ 9 } else if ( 10 shouldObserve && 11 !isServerRendering() && 12 (Array.isArray(value) || isPlainObject(value)) && 13 Object.isExtensible(value) && 14 !value._isVue 15 ) { 16 // 实例化Observer响应式对象 17 ob = new Observer(value) 18 } 19 if (asRootData && ob) { 20 ob.vmCount++ 21 } 22 return ob 23}
Observer
类
1export class Observer { 2 value: any; 3 dep: Dep; 4 vmCount: number; // number of vms that have this object as root $data 5 6 constructor (value: any) { 7 this.value = value 8 this.dep = new Dep() 9 this.vmCount = 0 10 def(value, '__ob__', this) 11 if (Array.isArray(value)) { 12 if (hasProto) { 13 protoAugment(value, arrayMethods) 14 } else { 15 copyAugment(value, arrayMethods, arrayKeys) 16 } 17 this.observeArray(value) 18 } else { 19 // 实例化对象是一个对象,进入walk方法 20 this.walk(value) 21 } 22}
walk
函数
1walk (obj: Object) { 2 const keys = Object.keys(obj) 3 // 遍历key,通过defineReactive创建响应式对象 4 for (let i = 0; i < keys.length; i++) { 5 defineReactive(obj, keys[i]) 6 } 7}
defineReactive
方法
1export function defineReactive ( 2 obj: Object, 3 key: string, 4 val: any, 5 customSetter?: ?Function, 6 shallow?: boolean 7) { 8 const dep = new Dep() 9 10 const property = Object.getOwnPropertyDescriptor(obj, key) 11 if (property && property.configurable === false) { 12 return 13 } 14 15 // cater for pre-defined getter/setters 16 const getter = property && property.get 17 const setter = property && property.set 18 if ((!getter || setter) && arguments.length === 2) { 19 val = obj[key] 20 } 21 22 let childOb = !shallow && observe(val) 23 // 接下来调用Object.defineProperty()给对象定义响应式属性 24 Object.defineProperty(obj, key, { 25 enumerable: true, 26 configurable: true, 27 get: function reactiveGetter () { 28 const value = getter ? getter.call(obj) : val 29 if (Dep.target) { 30 dep.depend() 31 if (childOb) { 32 childOb.dep.depend() 33 if (Array.isArray(value)) { 34 dependArray(value) 35 } 36 } 37 } 38 return value 39 }, 40 set: function reactiveSetter (newVal) { 41 const value = getter ? getter.call(obj) : val 42 /* eslint-disable no-self-compare */ 43 if (newVal === value || (newVal !== newVal && value !== value)) { 44 return 45 } 46 /* eslint-enable no-self-compare */ 47 if (process.env.NODE_ENV !== 'production' && customSetter) { 48 customSetter() 49 } 50 // #7981: for accessor properties without setter 51 if (getter && !setter) return 52 if (setter) { 53 setter.call(obj, newVal) 54 } else { 55 val = newVal 56 } 57 childOb = !shallow && observe(newVal) 58 // 对观察者watchers进行通知,state就成了全局响应式对象 59 dep.notify() 60 } 61 }) 62}
最近更新时间:2024-08-10