I have been in contact with angularjs a long time ago. At that time, I learned that angularjs uses dirty checks to realize data monitoring and page update rendering. After that, I got in touch again. At that time, I was curious about how to monitor data updates and re-render the page. Today, let’s analyze the principles of responsiveness step by step and implement a simple demo.
First, let’s learn some basic knowledge first.
Basic knowledge
es5 has added this API, which allows us to set getters and setters for the object's properties, so that we can hijack the user's values and assignments to object properties. For example, the following code:
const obj = { }; let val = 'cjg'; (obj, 'name', { get() { ('Hidden your value operation'); return val; }, set(newVal) { ('Hidden your assignment operation'); val = newVal; } }); (); = 'cwc'; ();
We hijacked the value and assignment operations of obj[name], so we can do some tricks here. For example, we can trigger the update page operation when obj[name] is assigned.
Publish subscription model
The publishing and subscription model is a common type of design model, with two roles: publisher and subscriber. Multiple subscribers can subscribe to an event to the same publisher. When the event occurs, the publisher notifies all subscribers who subscribe to the event. Let’s take a look at an example.
class Dep { constructor() { = []; } // Add subscribers addSub(sub) { if ((sub) < 0) { (sub); } } // Notify subscribers notify() { ((sub) => { (); }) } } const dep = new Dep(); const sub = { update() { ('sub1 update') } } const sub1 = { update() { ('sub2 update'); } } (sub); (sub1);
(); // Notify subscribers of the event to occur and trigger their update function
Hands-on practice
After we understand and publish the subscriber model, it is not difficult for us to imagine that data monitoring is based on the above two.
1. First, getter and setter hijack the data to be listened to. When the attributes of the data are assigned/valued, you can detect and perform corresponding processing.
2. Through the subscription publishing mode, we can create a publisher for each property of the object. When other subscribers rely on this property, the subscriber will be added to the publisher's queue. The data hijacking is used. When the setter of the property is called, the publisher of the property notifies all subscribers to update the content.
Next, let’s start the implementation (see the comments for details):
class Observer { constructor(data) { // If it is not an object, return if (!data || typeof data !== 'object') { return; } = data; (); } // Perform data hijacking on incoming data walk() { for (let key in ) { (, key, [key]); } } // Create a publish instance of the current attribute, and use it to perform data hijacking on the current attribute. defineReactive(obj, key, val) { // Create the publisher of the current attribute const dep = new Dep(); /* * Recursively hijack the values of sub-properties, for example, the following data * let data = { * name: 'cjg', * obj: { * name: 'zht', * age: 22, * obj: { * name: 'cjg', * age: 22, * } * }, * }; * We first hijack the outermost data name and obj, and then hijack the sub-properties of the obj object, and recurse them layer by layer until all data completes the data hijacking work. */ new Observer(val); (obj, key, { get() { // If there is currently a dependency on this property, add it to the publisher's subscriber queue if () { (); } return val; }, set(newVal) { if (val === newVal) { return; } val = newVal; new Observer(newVal); (); } }) } } // Publisher will add all watchers that depend on this property to the subs array. When the property changes, all watchers that depend on this property will be updated to trigger updates.class Dep { constructor() { = []; } addSub(sub) { if ((sub) < 0) { (sub); } } notify() { ((sub) => { (); }) } } = null; // Observerclass Watcher { /** *Creates an instance of Watcher. * @param {*} vm * @param {*} keys * @param {*} updateCb * @memberof Watcher */ constructor(vm, keys, updateCb) { = vm; = keys; = updateCb; = null; (); } // Get the latest observations based on vm and keys get() { = this; const keys = ('.'); let value = ; (_key => { value = value[_key]; }); = value; = null; return ; } update() { const oldValue = ; const newValue = (); if (oldValue !== newValue) { (oldValue, newValue); } } } let data = { name: 'cjg', obj: { name: 'zht', }, }; new Observer(data); // Listen to the name attribute of the data object. When a change is found, trigger the cb functionnew Watcher(data, 'name', (oldValue, newValue) => { (oldValue, newValue); }) = 'zht'; // Listen to the properties of the data object. When a change is found, the cb function will be triggered.new Watcher(data, '', (oldValue, newValue) => { (oldValue, newValue); }) = 'cwc'; = 'dmh';
Conclusion
In this way, a simple responsive data listening is completed. Of course, this is just a simple demo to illustrate the principle of responsiveness. The real source code will be more complicated because a lot of other logic is added.
Next I might associate it with html, implementing v-model, computed, and {{}} syntax.Code AddressIf you are interested, please come and discuss it together.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.