JavaScript data binding implements a simple MVVM library _javascript technique

Source: Internet
Author: User

Recommended reading:

Implementation of very simple JS bidirectional data binding

MVVM is a very popular development model for the Web front-end, and using MVVM enables our code to focus more on dealing with business logic than on DOM operations. The current well-known MVVM framework has Vue, Avalon, react, and so on, these frameworks are different, but the implementation of the idea is roughly the same: data binding + View refresh. Out of curiosity and a willing to toss the heart, I have also written in this direction the simplest MVVM library (mvvm.js), a total of more than 2000 lines of code, the naming and use of instructions and Vue similar, here to share the implementation of the principle and my Code organization ideas.

Idea Finishing

MVVM is conceptually a pattern that separates views from data logically, and ViewModel is the focus of the whole pattern. To implement ViewModel, you need to correlate the data model with the view, and the whole idea can be summed up in 5 simple points:

The implementation of a Compiler to the elements of each node of the instructions to scan and extract;

Implement a Parser to parse the instructions on the elements, to be able to update the intention of the instruction through a refresh function to the DOM (in the middle may need a special responsibility for the View Refresh module) such as parsing node <p v-show= "Isshow" ></p> first get Model in the Isshow value, and then according to Isshow change Node.style.display so as to control the display and concealment of elements;

Realizing a watcher can link the refresh function of each instruction in the Parser with the field corresponding to the Model;

The implementation of a Observer makes it possible to monitor the value of all the fields of an object, and when it changes, it can get the latest value and trigger the notification callback;

The use of Observer in the watcher to establish a model of the monitoring, when a value in model changes, monitoring is triggered, watcher get the new value after the call in step 2 associated with the Refresh function, you can realize the data changes while refreshing the view of the purpose.

Effects sample

First look at the final use example, similar to other MVVM framework instantiation:

<div id= "Mobile-list" >

Module Division

I divided the MVVM into five modules to achieve: Compiling module Compiler, parsing module Parser, view refresh Module Updater, data subscription module watcher and data listening module OBSERVER. The process can be summarized as follows: Compiler compiled instructions to the parser Parser resolution, Parser update the initial value and to the watcher subscription data changes, Observer monitoring the changes in the data and then feedback to watcher, watcher The change result is then notified updater to find the corresponding refresh function to refresh the view.

The above process is shown in the figure:

The following is a description of the basic principles of the implementation of these five modules (code only paste the key parts, complete implementation please go to my Github to read)

1. Compile Module Compiler

Compiler's responsibility is to scan and extract the instructions for each node of the element. Because the compilation and parsing process traverses the entire node tree more than once, in order to improve compilation efficiency, the element is first converted into a document fragment form within the MVVM constructor fragment the object is the document fragment and not the target element. After all the nodes have been compiled, add the document fragment back to the original real node.

Vm.complieelement implements scanning and instruction extraction for all nodes of the element:

Vm.complieelement = function (fragment, root) {
var node, childnodes = Fragment.childnodes;
Scan child node for
(var i = 0; i < childnodes.length i++) {
node = childnodes[i];
if (this.hasdirective (node)) {this
. $unCompileNodes. Push (node);
Recursively scans child nodes
if (node.childNodes.length) {
this.complieelement (node, false);
}
}
Scan complete, compile all nodes that contain instructions
if (root) {
this.compileallnodes ();
}
}

The Vm.compileallnodes method compiles each node in this. $unCompileNodes (handing instruction information to Parser), removes it from the cache queue after compiling one node, and checks this.$ Uncompilenodes.length when the length = = 0 O'Clock describes all compilation complete, you can append the document fragment to the real node.

2. Instruction parsing module Parser

When the compiler Compiler the instructions for each node, it can be parsed by the parser. Each instruction has a different parsing method, all the instructions of the parsing method to do two things: one is to update the data value to the view (initial state), and the second is to subscribe to the Model change monitoring. Here, an example of parsing v-text is used to describe an approximate method of parsing an instruction:

Parser.parsevtext = function (node, model) {
//Get the initial value defined in model 
var text = this. $model [model];
Update the node's text
node.textcontent = text;
Corresponding refresh function:
//updater.updatenodetextcontent (node, text);
Subscribe to model changes in watcher
Watcher.watch (model, function (last, old) {
node.textcontent = last;
Updater.updatenodetextcontent (node, text);}

3. Data Subscription Module Watcher

In the last example, Watcher provides a watch method to subscribe to data changes, one parameter is model field mode and the other is a callback function, which is to be triggered by the Observer, and the parameters are passed in the new value last and old, watcher get the new value You can find the model's corresponding callback (refresh function) to update the view. Model and Refresh function is a one-to-many relationship, that is, a model can have any number of callback functions to handle it (refresh function), such as: v-text= "title" and V-html= "title" Two instructions share a data model field.

To add a data subscription Watcher.watch implemented in the following ways:

Watcher.watch = function (field, callback, context) {
var callbacks = this. $watchCallbacks;
if (! Object.hasOwnProperty.call (this. $model, field)} {
Console.warn (' field: ' + field + ' does not exist in model! '); return
;
}
Set the cache callback function array
if (!callbacks[field]) {
Callbacks[field] = [];
}
Cache callback function
Callbacks[field].push ([callback, context]);
}

When the field field of the data model changes, watcher triggers all callbacks that subscribe to field in the cached array.

4. Data Listening module Observer

Observer is the core of the entire MVVM implementation, read an article that o.o (Object.observe) will detonate the data-binding revolution, to bring great influence on the front, but unfortunately, the ES7 draft has been abandoned O.O! Currently there is no browser support! Fortunately, there are object.defineproperty. You can simulate a simple Observer by intercepting the accessor descriptor (get and set) of the object's properties:

The Get and set method
Object.defineproperty (object, prop, {
get:function () {return
this.getva) of the prop property of the Block object. Lue (object, prop);
},
set:function (newvalue) {
var oldValue = This.getvalue (object, prop)
; if (newvalue!== oldValue) {
This.setvalue (object, newvalue, prop);
Trigger Change callback
This.triggerchange (prop, NewValue, OldValue);}}
);

Then there is the question of how to monitor array operations (push, shift, and so on). All MVVM frameworks are implemented by overriding the array's prototypes:

Observer.rewritearraymethods = function (array) {
var self = this;
var arrayproto = Array.prototype;
var arraymethods = object.create (Arrayproto);
var methods = ' Push|pop|shift|unshift|splice|sort|reverse '. Split (' | ');
Methods.foreach (function (method) {
Object.defineproperty (arraymethods, method, function () {
var i = Arguments.length;
var original = Arrayproto[method];
var args = new Array (i);
while (i--) {
args[i] = arguments[i];
}
var result = Original.apply (this, args);
Trigger Callback
Self.triggerchange (this, method);
return result;
};
})
; array.__proto__ = Arraymethods;
}

This implementation is from the Vue reference to the use of very good, but the length of the array can not be heard, so in the MVVM should avoid operation Array.Length

5. View Refresh Module Updater

Updater is the simplest in five modules, and only needs to be responsible for the refresh function for each instruction. The other four modules go through a series of toss and leave the final results to updater for a view or event update, such as the V-text refresh function:

updater.updatenodetextcontent = function (node, text) {
node.textcontent = text;
}

V-bind:style Refresh function:

Updater.updatenodestyle = function (node, propperty, value) {
Node.style[propperty] = value;
}

Implementation of bidirectional data binding

Bidirectional data binding for form elements is one of the biggest features of MVVM:

In fact, this magical function of the realization of the principle is very simple, there are only two things to do: one is the data changes when updating the form value, the second is the change in the form of the value of the data, so that the value of the data and the value of the form tied together.

Data changes update form values It is easy to make use of the Watcher module described above:

Watcher.watch (model, function (last, old) {
input.value = last;
});

Form change update data only needs to monitor the form's worthwhile events in real time and update the data model corresponding fields:

var model = this. $model;
Input.addeventlistenr (' Change ', function () {
Model[field] = this.value;
}); '

Other Forms radio, checkbox and select are the same principle.

Above, the whole process and the basic realization of each module is finished, the first time in the community to send articles, language ability is not very good, such as the wrong writing of the bad place, I hope we can criticize correct!

Conclusion

Toss this simple mvvm.js is because the original frame project used by the Vue.js but only use its command system, a large pile of functions to use only about One-fourth, just to realize data-binding and View-refresh is enough, the results did not find such a JavaScript library, so I built such a wheel myself.

Although the function and stability is far inferior to the popular MVVM frame such as Vue, the code realization may also be more rough, but by making this wheel or has grown a lot of knowledge ~ Progress lies in Toss it!

At present, my mvvm.js just realize the most of the function, I will continue to improve, robust it, if interested in welcome to discuss and improve ~

Related Article

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.