Detailed description of Vue event driver and dependency tracking, detailed description of vue event tracking

Source: Internet
Author: User

Detailed description of Vue event driver and dependency tracking, detailed description of vue event tracking

A previous analysis on Vue data binding principles needs to be reviewed recently and sent to the essay by the way.

In the previous implementation of an Mvvmsetter To observemodel.viewModel Bindmodel . WhenmodelChange, update allviewModelTo render the new value to the interface. At the same time, throughv-model All boundinputAnd passaddEventListenerEvent will be updatedmodel To complete two-way binding.

But that program is not only used to understanddefinePropertyAnd others are worthless.

  1. No compilation node.
  2. No processing expression dependency.

Here I will solve the problem of expression dependency. I will introduce the vue template compilation in the next section.

Define getter & setter for Data

class Observer { constructor(data) {  this._data = data;  this.walk(this._data); } walk(data) {  Object.keys(data).forEach((key) => { this.defineRective(data, key, data[key]) }) }; defineRective(vm, key, value) {  var self = this;  if (value && typeof value === "object") {   this.walk(value);  }  Object.defineProperty(vm, key, {   get: function() {    return value;   },   set: function(newVal) {    if (value != newVal) {     if (newVal && typeof newVal === "object") {      self.walk(newVal);     }     value = newVal;    }   }  }) }}module.exports = Observer;

In this way, each attribute is addedgetter Andsetter When the attribute is an object, it is recursively added.

Once the attribute value is obtained or assigned a value to the attributeget Orset Whenset, That ismodelYou can publish a message to notify allviewModel Update.

DefineRective (vm, key, value) {// stores the dependency expression of this attribute in the closure. Var dep = new Dep (); var self = this; if (value & typeof value = "object") {this. walk (value);} Object. defineProperty (vm, key, {get: function () {return value;}, set: function (newVal) {if (value! = NewVal) {if (newVal & typeof newVal = "object") {self. walk (newVal);} value = newVal; // notify all viewmodels to update dep. notify ();}}})}

How to defineDep What about ??

Class Dep {constructor () {// dependency list this. dependences = [];} // Add dependency addDep (watcher) {if (watcher) {this. dependences. push (watcher) ;}}// notify all dependencies to update notify () {this. dependences. forEach (watcher) => {watcher. update () ;}} module. exports = Dep;

Each dependency here isWatcher .

See how to defineWatcher

EachWatcher There will be a uniqueidIt has an expression and a callback function.

For example, expression a +b; Will be accessed during get computinga Andb Because JavaScript is a single thread, only one JavaScript code is executed at any time.Dep.target As a global variable to indicate the currentWatcher And thencompute Accessa ,b , Triggera Andb OfgetterIn getter Dep.target Add as dependency.

Oncea Andb Ofset Trigger, callupdate Function to update the dependent value.

Var uid = 0; class Watcher {constructor (viewModel, exp, callback) {this. viewModel = viewModel; this. id = uid ++; this. exp = exp; this. callback = callback; this. oldValue = ""; this. update ();} get () {Dep.tar get = this; var res = this. compute (this. viewModel, this. exp); Dep.tar get = null; return res;} update () {var newValue = this. get (); if (this. oldValue = newValue) {return;} // update Dom in callback this. callback (newValue, this. oldValue); this. oldValue = newValue;} compute (viewModel, exp) {var res = replaceWith (viewModel, exp); return res ;}} module. exports = Watcher;

Because the current expression needs to be executed under the current model, replaceWith function is used to replace.

Add dependency through get

Object.defineProperty(vm, key, { get: function() {  var watcher = Dep.target;  if (watcher && !dep.dependences[watcher.id]) {   dep.addDep(watcher);  }  return value; }, set: function(newVal) {  if (value != newVal) {   if (newVal && typeof newVal === "object") {    self.walk(newVal);   }   value = newVal;   dep.notify();  } }})

This method of adding dependencies is too clever.

Here I drew a picture to describe it.

Finally, let's test the code.

const Observer = require('./Observer.js');const Watcher = require('./watcher.js');var data = { a: 10, b: {  c: 5,  d: {   e: 20,  } }}var observe = new Observer(data);var watcher = new Watcher(data, "a+b.c", function(newValue, oldValue) { console.log("new value is " + newValue); console.log("oldValue is " + oldValue);});console.log("\r\n");console.log("a has changed to 50,then the expr should has value 55");data.a = 50;console.log("\r\n");console.log("b.c has changed to 50,then the expr should has value 122");data.b.c = 72;;console.log("\r\n");console.log("b.c has reseted an object,then the expr should has value 80");data.b = { c: 30 }

OK

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.