Analysis of vue data binding

  • 2021-07-12 04:54:09
  • OfStack

Recently, the team needs to do a sharing, and they don't know how to share. Finally, thinking about the previous 1 straight want to study 1 vue source code, today just "take this opportunity" to study 1.

There are a lot of articles about vue data binding on the Internet, but it is completely different to write and knock demo once and read other people's articles. so … … The porter is here

At present, there are mainly three ways to implement data binding:

1. Dirty value check (angular. js) polling to detect data changes

DOM events, such as user entering text, clicking buttons, and so on. (ng-click)

XHR Response Event ($http) Browser Location Change Event ($location) Timer Events ($timeout, $interval) Execute $digest () or $apply ()

2. Object. defineProperty hijacks get and set of objects, thus realizing data monitoring. (vue)

3. Publish/Subscriber Mode realizes automatic synchronization between data and view

Object. Advantages of defineProperty

"Dirty value detection"-after the data changes, For all the data and view binding relationship to detect once, identify whether there is a change in the data, change processing, may lead to other data changes, so this process may be cycled several times, 1 until no more data changes occurred, the changed data will be sent to the view, update the page presentation Object. defineProperty () monitors operations on data and automatically triggers data synchronization. Moreover, because synchronization is triggered on different data, changes can be accurately sent to the bound view, instead of performing one detection on all data.

Object. Usage of defineProperty


var a = {};

Object.defineProperty(a, "b", {
 
 set: function (newValue) {
 
 console.log(" I've been assigned a value! " + newValue);
 
 },
 
 get: function () {
 
 console.log(" I've been valued! ");
 
 return 2 
 }
})

a.b = 3; // I've been assigned a value! 

console.log(a.b); // I was valued ! // Print  2

From the above example, we can see that Object. defineProperty has three parameters

Number 1: a object

Second: b attribute in a object

Third: There are many attributes, listing useful value, set, get and configurable

Data binding principles:

1. Implement a data listener Observer to monitor all the attributes of the data object. If there is any change, get the latest value and notify the dep array

2. Implement an instruction parser Compile, which scans and parses the instructions of each element node and replaces the data according to the instruction template

3. Implement an dep array, which can subscribe and receive the notification of each attribute change, execute the corresponding callback function bound by instructions, and update the view

1. Implement observer


var data = {name: 'beidan'};

observe(data);

data.name = 'test'; //  Listen to the value change  beidan  Become  test

function observe(data) {
 
 if (!data || typeof data !== 'object') {
 
 return;
 
 }
 
 //  Fetch all attributes to traverse 
 
 Object.keys(data).forEach(function(key) {
 
  defineReactive(data, key, data[key]);

 });
}

function defineReactive(data, key, val) {


 Object.defineProperty(data, key, {

 enumerable: true, //  Enumerable 
 
  configurable: false, //  Can no longer define
  get: function() {
  
   return val;
 
  },
 
  set: function(newVal) {
  
   console.log(' Listen to the value change  ', val, '  Become  ', newVal);

   val = newVal;
 
  }
 
 });
}

2. Maintain an array


function Dep() {
 
 this.subs = [];
}

Dep.prototype = {
 
 addSub: function (sub) {
 
 this.subs.push(sub);
 
 },
 
 notify: function (val) {
 
  this.subs.forEach(function (sub) {
  
  sub.update(val)
 
 });
 
}
};
function defineReactive(data, key, val) {
 Object.defineProperty(data, key, {
  ... 
 set: function(newVal) {
  if (val === newVal) return;
  console.log(' Listen to the value change  ', val, '  Become  ', newVal);
  val = newVal;
  dep.notify(val); //  Notify all subscribers  
 } 
 });
}

3. compile


bindText: function () {
 
 var textDOMs = this.el.querySelectorAll('[v-text]'),
bindText,_context = this;

 
 for (var i = 0; i < textDOMs.length; i++) {
  
 bindText = textDOMs[i].getAttribute('v-text');
 textDOMs[i].innerHTML = this.data[bindText];

 var val = textDOMs[i]

 
 var up = function (text) {
  
  val.innerText = text
 
 }

 _context.dep.addSub({
  
  value: textDOMs[i],
  
  update: up
 
 });
 
 }
},

Finally, attach the source code github https://github.com/beidan/vue_bind

Reference link:

https://www.ofstack.com/article/103297.htm

https://www.ofstack.com/article/99129.htm


Related articles: