Manual Vue two-way data binding implementation

class Asarua {
   // passing an object is instantiated parameters
  constructor(options) {
    this.$data = options.data;
     // Get mounted dom
    this.$el = document.querySelector(options.el);
    this.$methods = options.methods;
    this.$options = options;
     // define a container to store all subscribers
    this.observable = {};
    this.initObservable();
    this.addObservable();
    this.observe();
  }
   // Initialize the container
  initObservable() {
    for (let i in this.$data) {
      this.observable[i] = [];
    }
  }
   // add a subscription
  addObservable() {
     // Get all the current level sub-node below
    const nodes = this.$el.children;
     // use a for loop, if it is for in will traverse some strange things;
    for (let i = 0; i < nodes.length; i++) {
       // determines whether there is a-model custom attributes
      if (nodes[i].hasAttribute("a-model")) {
         // Get the presence of elements a-model property
        const node = nodes[i];
         // Get the value of this element a-model, which is a subscription which property
        const prop = node.getAttribute("a-model");
         // found in the container after initialization this property, an instance of the observer added into the container, there is added to it while a refresh method
        this.observable[prop].push(new Watcher(node, "value", this, prop));
         // start listening, if the input event occurs, this. The value of this attribute $ data in the change, while the trigger interceptors, calling the update method to update the interceptor
        node.addEventListener("input", () => {
          this.$data[prop] = node.value;
        })
      };
      if (nodes[i].hasAttribute("a-text")) {
        const node = nodes[i];
        const prop = node.getAttribute("a-text");
        this.observable[prop].push(new Watcher(node, "innerText", this, prop));
      };
      if (nodes[i].hasAttribute("a-html")) {
        const node = nodes[i];
        const prop = node.getAttribute("a-html");
        this.observable[prop].push(new Watcher(node, "innerHTML", this, prop));
      };
       // If there @click, then add an event listener for the current element, this. Method on the $ methods called when clicked, while the scope to point this. $ Data, so that it can pass this. The $ data access Attributes
      if (nodes[i].hasAttribute("@click")) {
        const node = nodes[i];
        const prop = node.getAttribute("@click");
        node.addEventListener("click",()=>{
          this.$methods[prop].call(this.$data);
        })
      };
    }
  }
  observe() {
    const _this = this;
     // Loop container, add the attribute to each interceptor
    for (let i in this.$data) {
      let _value = this.$data[i];
       // intercept this. $ Data each property, if the value of the direct return, if it is set, first determine whether or not the same as before and, if different, will replace the old value to the new value, and update method is called real-time refresh
      Object.defineProperty(this.$data, i, {
        get() {
          return _value;
        },
        set(v) {
          if (_value !== v) {
            _value = v;
            _this.observable[i].forEach(v => v.update())
          }
        }
      })
    }
  }
}
class Watcher {
   // four parameters received, to update the current element, to update the attributes of the class above example, listening properties
  builder (what, about, year, attr) {
    this.el = the;
    this.prop = prop;
    this.any = any;
    this.attr = attr;
    this.update();
  }
   // update function is invoked, so that the current value of the current element becomes the current value of the attribute data in the attribute
  update() {
    this.el[this.prop] = this.any.$data[this.attr];
  }
}

// First, get all the properties of the resulting instantiated, then each data options are creating a subscription actors.
// Next attribute determines whether there is a custom two-way data binding, if present, it is added to the attribute value
// corresponding subscribers container. While being bound dom, its properties to be changed, and the changed values, as well as a method of synchronizing the current value of the current property value and the data in dom passed in order to be able to change the dom directly when called value.
// then to add an event listener, observing trends, if you change the value of the dom in the value of data in the change
// add interceptors for all properties in the data, and if the value of the current value of the data is returned, if it is set up, after the incoming data value is set to a value, called the current property container of all subscriptions update's method,
// The value of the data after the change, all assigned to use this value data dom, change its properties
 
So many things speaking on a two-step
The first step, input value added changes to the subscriber's own values
2. Add value itself after a change in the value of the property all current subscribers to modify interceptors

Guess you like

Origin www.cnblogs.com/asablog/p/11365982.html