This article mainly introduces a brief discussion on the principle of Vue data responsiveness, which has certain reference value. Now I share it with you. Friends in need can refer to it
Preface
Vue's data response mainly relies on Object.defineProperty(), so what is the whole process like? Taking the path of Vue with our own ideas actually means taking the principles of Vue as the end point. Let's reverse the implementation process.
The codes in this article are all low-configuration versions, and many places are not rigorous. For example, if(typeof obj === 'object') is to determine whether obj is an object, although obj may also be an array, etc. Other types of data, but for the sake of simplicity, this article will write it directly to represent the judgment object. For arrays, use Array.isArray().
Transform data
Let’s first try to write a function for transforming objects:
Why should we write this first? What about functions? Because transforming data is the most basic and important step, all subsequent steps will depend on this step.
// 代码 1.1 function defineReactive (obj,key,val) { Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function () { return val; }, set: function (newVal) { //判断新值与旧值是否相等 //判断的后半段是为了验证新值与旧值都为NaN的情况 NaN不等于自身 if(newVal === val || (newVal !== newVal && value !== value)){ return ; } val = newVal; } }); }
For example, const obj = {}, and then call the defineReactive(obj,'a',2) method. At this time, within the function, val=2 , then every time you get the value of obj.a, you get the value of val, and when you set obj.a, you also set the value of val. (Every call to defineReactive will generate a closure to save the value of val);
Process Discussion
After verification, I found that this function can indeed be used. Then let’s discuss the response process:
Input data
Transform data (defineReactive() )
If the data changes=> trigger event
Let’s look at the third step. How does the data change trigger subsequent events? Think about it carefully, if you want to change the data, you must set the data first, then we can just add the method to set() and it will be ok.
Then there is another important question:
Dependency Collection
How do we know what event will be triggered after the data changes? In Vue:
Use data => View; Data is used to render the view, so it is the best time to collect dependencies when obtaining data. Vue generates a Dep instance, used to collect dependencies.
// 代码 1.2 class Dep { constructor(){ //订阅的信息 this.subs = []; } addSub(sub){ this.subs.push(sub); } removeSub (sub) { remove(this.subs, sub); } //此方法的作用等同于 this.subs.push(Watcher); depend(){ if (Dep.target) { Dep.target.addDep(this); } } //这个方法就是发布通知了 告诉你 有改变啦 notify(){ const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update(); } } } Dep.target = null;
Code 1.2 is part of the code of Dep. For the time being, you only need to know the functions of 2 methods
depend() --- It can be understood as collecting dependent events. Without considering other aspects, the function is equivalent to addSub()
notify() --- This method is more For clarity, execute the update() method of all dependencies. Just change the view later and so on.
This article mainly discusses the process of data response and does not discuss the Watcher class in depth, so you only need to know the functions of the methods in Dep.
Then it’s time to change the code 1.1
//代码 1.3 function defineReactive (obj,key,val) { const dep = new Dep(); Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function () { if(Dep.target){ //收集依赖 等同于 dep.addSub(Dep.target) dep.depend() } return val; }, set: function (newVal) { if(newVal === val || (newVal !== newVal && val !== val)){ return ; } val = newVal; //发布改变 dep.notify(); } }); }
There is a doubt in this code, what is Dep.target? Why do we need Dep.target to collect dependencies?
Dep is a class, and Dep.target is an attribute of the class, not an attribute of the dep instance.
The Dep class is available globally, so Dep.target can be accessed globally and its value can be changed arbitrarily.
get This method is very common to use, and it is impossible to call dep.depend() every time you use it to obtain data values.
dep.depend() is actually dep.addSub(Dep.target).
The best way is to set Dep.target to an object before use, and set Dep.target = null after the subscription is completed.
Verification
It’s time to verify the availability of a wave of codes
//代码 1.4 const obj = {};//这一句是不是感觉很熟悉 就相当于初始化vue的data ---- data:{obj:{}}; //低配的不能再低配的watcher对象(源码中是一个类,我这用一个对象代替了) const watcher = { addDep:function (dep) { dep.addSub(this); }, update:function(){ html(); } } //假装这个是渲染页面的 function html () { document.querySelector('body').innerHTML = obj.html; } defineReactive(obj,'html','how are you');//定义响应式的数据 Dep.target = watcher; html();//第一次渲染界面 Dep.target = null;
The interface on the browser is like this
Then open the console below to start debugging, enter:
obj.html = 'I am fine thank you'
Then I discovered that the moment I pressed Enter, a miracle happened and the page became
End
The design pattern of Vue data response is somewhat similar to the subscription publishing pattern, but different. Each dep instance is a subscription. Center, every publication will publish all subscriptions.
There is actually a large part of Vue's responsiveness principle. This article mainly discusses how Vue allows data to respond. But in fact, there is generally a lot of data. One data is used in many places. Observe after changing the data. New values, how to observe, how to subscribe, how to schedule, there are still a lot of things that have not been discussed. The three main classes, Dep (collecting dependencies), Observer (observing data), and Watcher (subscribers, notifying subscribers if data changes), have only been mentioned a little bit.
I previously wrote an article about Vue responsiveness - array mutation method, which discusses the transformation of arrays in Vue. Of course, there will be more other articles later, and there is still a lot of content in the entire data response process, and the three main classes have not been discussed yet.
In fact, reading the source code is not only to know how the source code works, but more importantly, to learn the author’s ideas and methods. The articles I write are not long, and I hope that I can focus on one point at a time. , can truly understand the principle of this point. Of course, I also want to control the reading time so that people don’t close it after reading it halfway through.
Related recommendations:
Summary of vue data transfer methods
##Detailed explanation of vue data transfer implementation steps
Usage of Vue data listening method watch
The above is the detailed content of A brief discussion on the principle of Vue data responsiveness. For more information, please follow other related articles on the PHP Chinese website!