In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly introduces the Vue2 responsive system how to make the array effective related knowledge, the content is detailed and easy to understand, the operation is simple and fast, has a certain reference value, I believe that after reading this Vue2 responsive system how to make the array effective article will have a harvest, let's take a look at it.
1. Scene import {observe} from ". / reactive"; import Watcher from ". / watcher"; const data = {list: ["hello"],}; observe (data); const updateComponent = () = > {for (const item of data.list) {console.log (item);}}; new Watcher (updateComponent); data.list = ["hello", "liang"]
First, you can think about what will be output for a minute.
Although the value is an array, we assign it as a whole, so it will still be triggered, and the trigger will be reexecuted. The output is as follows: listdata.listdata.listsetWatcher
2. Scene 2import {observe} from ". / reactive"; import Watcher from ". / watcher"; const data = {list: ["hello"],}; observe (data); const updateComponent = () = > {for (const item of data.list) {console.log (item);}}; new Watcher (updateComponent); data.list.push ("liang")
First, you can think about what will be output for a minute.
This time the method is called, but we didn't do anything to the method, so it won't be triggered. PushpushWatcher
3. Plan
In order for other methods of the array to work, we need to rewrite them. Through the push proxy mode, we can save the original methods of the array, then execute them, and add our own extra operations.
/ * * not type checking this file because flow doesn't play well with * dynamically accessing methods on Array prototype * / / * export function def (obj, key, val, enumerable) {Object.defineProperty (obj, key, {value: val, enumerable:! enumerable, writable: true, configurable: true,});} * / import {def} from ". / util"; const arrayProto = Array.prototype;export const arrayMethods = Object.create (arrayProto) Const methodsToPatch = ["push", "pop", "shift", "unshift", "splice", "sort", "reverse",]; / * Intercept mutating methods and emit events * / methodsToPatch.forEach (function (method) {/ / cache original method const original = arrayProto [method]; def (arrayMethods, method, function mutator (... args) {const result = original.apply (this, args) / * this is equivalent to calling the object set and needs to notify watcher * * / / to be added / * * * * / return result );})
When an array or other method is called, it is equivalent to rewriting the property before, and what needs to be added above is in the notification. PushsetdepWatcher
Export function defineReactive (obj, key, val, shallow) {const property = Object.getOwnPropertyDescriptor (obj, key); / / read get, set const getter = property & & property.get; const setter = property & & property.set; / / val that the user may have defined by himself, if ((! getter | | setter) & & arguments.length = = 2) {val = obj [key] } const dep = new Dep (); / / holds a Dep object that holds all Watcher let childOb =! shallow & & observe (val) that depend on this variable; Object.defineProperty (obj, key, {enumerable: true, configurable: true, get: function reactiveGetter () {const value = getter? Getter.call (obj): val; if (Dep.target) {dep.depend ();} return value;}, set: function reactiveSetter (newVal) {const value = getter? Getter.call (obj): val; if (setter) {setter.call (obj, newVal);} else {val = newVal;} dep.notify ();},});}
As in the code above, the previous one is through closures, and each property has its own one, which is responsible for collecting and notifying. DepdepWatcherWatcher
So for arrays, where is it easier for us to put it? Dep
Recall the current structure.
Const data = {list: ["hello"],}; observe (data); const updateComponent = () = > {for (const item of data.list) {console.log (item);}}; new Watcher (updateComponent)
After the above code is executed, it will be the structure of the following figure.
The list attribute has the property in the closure, and through the collection, the. Depnew WatcherupdateCompnentWatcher
At the same time, because it is an array, that is, an object, we know from the deep response (opens new window) of the listvalue ["hello"] responsive system in the previous article that it will also call functions. Observer
So, should I just add one in? ObserverDep
In this way, when we call the array method to modify the value, we can notify the value in it. ['hello'] ObserverDep
3. Collect dependent code implementation
According to the above ideas, improve the class. Observer
Export class Observer {constructor (value) {/ * add * / this.dep = new Dep (); / * / this.walk (value) } / * iterate through all the properties of the object, and call the get and set methods of defineReactive * intercepting object properties * / walk (obj) {const keys = Object.keys (obj); for (let I = 0; I)
< keys.length; i++) { defineReactive(obj, keys[i]); } }} 然后在 中,当前 中的 也去收集依赖。getOberverdep export function defineReactive(obj, key, val, shallow) { const property = Object.getOwnPropertyDescriptor(obj, key); // 读取用户可能自己定义了的 get、set const getter = property && property.get; const setter = property && property.set; // val 没有传进来话进行手动赋值 if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } const dep = new Dep(); // 持有一个 Dep 对象,用来保存所有依赖于该变量的 Watcher let childOb = !shallow && observe(val); Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { const value = getter ? getter.call(obj) : val; if (Dep.target) { dep.depend(); /******新增 *************************/ if (childOb) { // 当前 value 是数组,去收集依赖 if (Array.isArray(value)) { childOb.dep.depend(); } } /************************************/ } return value; }, set: function reactiveSetter(newVal) { const value = getter ? getter.call(obj) : val; if (setter) { setter.call(obj, newVal); } else { val = newVal; } dep.notify(); }, });}4、通知依赖代码实现 我们已经重写了 方法,但直接覆盖全局的 方法肯定是不好的,我们可以在 类中去操作,如果当前 是数组,就去拦截它的 方法。arrayarrrayObservervaluearray 这里就回到 的原型链上了,我们可以通过浏览器自带的 ,将当前对象的原型指向我们重写过的方法即可。js__proto__ 考虑兼容性的问题,如果 不存在,我们直接将重写过的方法复制给当前对象即可。__proto__ import { arrayMethods } from './array' // 上边重写的所有数组方法/* export const hasProto = "__proto__" in {}; */export class Observer { constructor(value) { this.dep = new Dep(); /******新增 *************************/ if (Array.isArray(value)) { if (hasProto) { protoAugment(value, arrayMethods); } else { copyAugment(value, arrayMethods, arrayKeys); } /************************************/ } else { this.walk(value); } } /** * 遍历对象所有的属性,调用 defineReactive * 拦截对象属性的 get 和 set 方法 */ walk(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]); } }}/** * Augment a target Object or Array by intercepting * the prototype chain using __proto__ */function protoAugment(target, src) { /* eslint-disable no-proto */ target.__proto__ = src; /* eslint-enable no-proto */}/** * Augment a target Object or Array by defining * hidden properties. *//* istanbul ignore next */function copyAugment(target, src, keys) { for (let i = 0, l = keys.length; i < l; i++) { const key = keys[i]; def(target, key, src[key]); }} 还需要考虑一点,数组方法中我们只能拿到 值,那么怎么拿到 对应的 呢。valuevalueObserver 我们只需要在 类中,增加一个属性来指向自身即可。Observe export class Observer { constructor(value) { this.dep = new Dep(); /******新增 *************************/ def(value, '__ob__', this) /************************************/ if (Array.isArray(value)) { if (hasProto) { protoAugment(value, arrayMethods); } else { copyAugment(value, arrayMethods, arrayKeys); } } else { this.walk(value); } } ...} 回到最开始重写的 方法中,只需要从 中拿到 去通知 即可。array__ob__DepWatcher /* * not type checking this file because flow doesn't play well with * dynamically accessing methods on Array prototype */import { def } from "./util";const arrayProto = Array.prototype;export const arrayMethods = Object.create(arrayProto);const methodsToPatch = [ "push", "pop", "shift", "unshift", "splice", "sort", "reverse",];/** * Intercept mutating methods and emit events */methodsToPatch.forEach(function (method) { // cache original method const original = arrayProto[method]; def(arrayMethods, method, function mutator(...args) { const result = original.apply(this, args); /*****************这里相当于调用了对象 set 需要通知 watcher ************************/ const ob = this.__ob__; // notify change ob.dep.notify(); /**************************************************************************** */ return result; });});5、测试import { observe } from "./reactive";import Watcher from "./watcher";const data = { list: ["hello"],};observe(data);const updateComponent = () =>{for (const item of data.list) {console.log (item);}}; new Watcher (updateComponent); data.list.push ("liang")
In this way, when the method is called, the corresponding function is triggered to execute the function. PushWatcherupdateComponent
The current dependency becomes something like this:
This is the end of the article on "how to make arrays work in Vue2 responsive systems". Thank you for reading! I believe you all have a certain understanding of the knowledge of "how to make arrays effective in Vue2 responsive systems". If you want to learn more, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.