This time I will show you how to use Vue to implement Observer, and what are the precautions for using Vue to implement Observer. The following is a practical case, let's take a look.
Introduction:
This article is an in-depth introduction to the responsive principles of Vue official documentation (The responsive principle can be divided into two steps, the process of relying on collection and the process of triggering and re-rendering. There are three very important classes in the dependency collection process, namely Watcher, Dep, and Observer. This article mainly explains Observer. This article explains the content of Observer that was not covered in the previous article. Let’s first look at this picture on the official website: The main function of Observer It realizes the process of touch -Data(getter) - Collect as Dependency in the picture above, which is the process of dependency collection. Let’s take the following code as an example to sort it out: (Note: Swipe left and right to view the complete code, the same below)varvm = newVue({ el: '#demo', data: { firstName: 'Hello', fullName: '' }, watch: { firstName(val) { this.fullName = val + 'TalkingData'; }, } })
// src/core/instance/index.js functionVue(options) { if(process.env.NODE_ENV !== 'production'&& !(thisinstanceofVue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) } // src/core/instance/init.js Vue.prototype._init = function(options?: Object) { constvm: Component = this // ... initState(vm) // ... } // src/core/instance/state.js exportfunctioninitState(vm: Component) { // ... constopts = vm.$options if(opts.data) { initData(vm) } // ... } functioninitData(vm: Component) { letdata = vm.$options.data data = vm._data = typeofdata === 'function' ? getData(data, vm) : data || {} // ... // observe data observe(data, true/* asRootData */) }
// src/core/observer/index.js functionobserve(value: any, asRootData: ?boolean): Observer| void{ // 如果不是对象,直接返回 if(!isObject(value) || value instanceofVNode) { return } letob: Observer | void if(hasOwn(value, 'ob') && value.ob instanceofObserver) { // 如果有实例则返回实例 ob = value.ob } elseif( // 确保value是单纯的对象,而不是函数或者是Regexp等情况 observerState.shouldConvert && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { // 实例化一个 Observer ob = newObserver(value) } if(asRootData && ob) { ob.vmCount++ } returnob }
exportclassObserver{ value: any; dep: Dep; vmCount: number; // number of vms that has this object as root $data constructor(value: any) { this.value = value this.dep = newDep() this.vmCount = 0 def(value, 'ob', this) if(Array.isArray(value)) { // ... this.observeArray(value) } else{ this.walk(value) } } walk (obj: Object) { constkeys = Object.keys(obj) for(leti = 0; i < keys.length; i++) { defineReactive(obj, keys[i], obj[keys[i]]) } } observeArray (items: Array<any>) { for(leti = 0, l = items.length; i < l; i++) { observe(items[i]) } } }
exportfunctiondefineReactive( obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean ) { constdep = newDep() // 获取属性的自身描述符 constproperty = Object.getOwnPropertyDeor(obj, key) if(property && property.configurable === false) { return } // cater for pre-defined getter/setters // 检查属性之前是否设置了 getter/setter // 如果设置了,则在之后的 get/set 方法中执行设置了的 getter/setter constgetter = property && property.get constsetter = property && property.set // 通过对属性再次调用 observe 方法来判断是否有子对象 // 如果有子对象,对子对象也进行依赖搜集 letchildOb = !shallow && observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: functionreactiveGetter() { // 如果属性原本拥有getter方法则执行 constvalue = getter ? getter.call(obj) : val if(Dep.target) { // 进行依赖收集 dep.depend() if(childOb) { // 如果有子对象,对子对象也进行依赖搜集 childOb.dep.depend() // 如果属性是数组,则对每一个项都进行依赖收集 // 如果某一项还是数组,则递归 if(Array.isArray(value)) { dependArray(value) } } } returnvalue }, set: functionreactiveSetter(newVal) { // 如果属性原本拥有getter方法则执行 // 通过getter方法获取当前值,与新值进行比较 // 如果新旧值一样则不需要执行下面的操作 constvalue = getter ? getter.call(obj) : val /* eslint-disable no-self-compare */ if(newVal === value || (newVal !== newVal && value !== value)) { return } /* eslint-enable no-self-compare */ if(process.env.NODE_ENV !== 'production'&& customSetter) { customSetter() } if(setter) { // 如果属性原本拥有setter方法则执行 setter.call(obj, newVal) } else{ // 如果原本没有setter则直接赋新值 val = newVal } // 判断新的值是否有子对象,有的话继续观察子对象 childOb = !shallow && observe(newVal) // 通知所有的观察者,更新状态 dep.notify() } }) }
How to use the vue file tree component
The above is the detailed content of How to implement Observer using Vue. For more information, please follow other related articles on the PHP Chinese website!