Mvvm-simple bidirectional binding is simple
bestvist 2018-04-17
MVVM mode frees the DOM shackles
MVVM principle analysis
JavaScript manipulating HTML in the browser goes through several different stages
The first stage directly manipulates DOM elements with native apis provided by the browser
var dom = document.getElementById('id');
dom.innerHTML = 'hello mvvm';
Copy the code
In the second stage, jQuery solves the complexity of native apis and compatibility between browsers, providing a simpler and more convenient API
$('#id').text('hello mvvm')
Copy the code
The third stage MVC pattern enables the front end to work with the back end to modify the page content rendered by the server
As products attach more importance to user experience, interactive experience becomes more and more important. JQuery alone is far from enough. MVVM Model solves the pain point of frequent operation, and model-view-ViewModel mode transfers data and View synchronization to ViewModel
JQuery Modify node content:
<p>name: <span id="name">vist</span>! </p> <p>age: <span id="age">25</span>.</p> var name = 'bestvist'; var age = 26; $('#name').text(name); $('#age').text(age);Copy the code
In MVVM mode, only the data structure needs to be concerned:
Var me = {name: 'vist', age: 25} me.age = 26;Copy the code
The MVVM implementation
MVVM implements data binding in several ways:
- Publish and subscribe
- Dirty value check
- The data was hijacked
The more popular VUE adopts the data hijacking and published-subscribe mode. By hijacking the get and set methods of each attribute in Object.defineProperty() provided by ES5, the message is triggered to the subscriber when the data is updated, and the data binding function is realized.
Object.defineproperty (obj, prop, Descriptor) methods directly define a new property on an Object, or modify an existing property, and return the Object. The method accepts three parameters:
- Obj The object that defines attributes.
- Prop Specifies the name of the property to be defined or modified.
- Descriptor Descriptor of a property to be defined or modified.
While properties are typically created or modified by assigning values directly to Object properties, using Object.defineProperty allows you to modify some additional default configurations of Object properties. Such as:
const obj = {name: 'Tom'}; Object.defineProperty(obj, 'name', { get: function(val) { return 'Jerry'; } }) console.log(obj.name); // Output: JerryCopy the code
Please stamp here
The main process of MVVM implementation:
- Data proxy, which directly returns properties in the corresponding data when accessing properties on the instance
- Data listening, which listens for properties on the instance and notifies subscribers of updates if data changes
- Instruction parsing, parsing each element node, replacing data and binding update functions
- Link data listening and instruction resolution to ensure that each data update, instruction resolution can obtain and update the view
Instantiate class:
new MVVM({
el: '#app',
data() {
return {
message: 'hello mvvm'
}
}
})
Copy the code
Data broker:
class MVVM { constructor(options) { this.$options = options || {}; let data = this._data = this.$options.data(); // Data agent vm. XXX => vm._data.xxx object.keys (data).foreach (key => {this._proxyData(key); }); // observe(data, this); // this.$compile = new Compile(options.el || document.body, this); } _proxyData(key) { Object.defineProperty(this, key, { configurable: true, enumerable: true, get: () => { return this._data[key]; }, set: newVal => { this._data[key] = newVal; }}); }}Copy the code
Data listening, hijacking instance property update
class Observer { constructor(data) { this.data = data; Object.keys(this.data).forEach(key => { this.defineReactive(key, this.data[key]); DefineReactive (key, val) {let dep = new dep (); Object.defineProperty(this.data, key, { enumerable: true, configurable: false, get: () => { return val; }, set: newVal => { if (val === newVal) { return; } val = newVal; // Assign the object to hijacking observe(val); . }} function observe(val) {if (! val || typeof val ! == 'object') { return; } return new Observer(val); }Copy the code
The instruction parses part of the code
class Compile { constructor(el, vm) { this.$vm = vm; this.$el = this.isElementNode(el) ? el : document.querySelector(el); if (this.$el) { this.$fragment = this.node2Fragment(this.$el); this.init(); this.$el.appendChild(this.$fragment); } } init() { this.compileElement(this.$fragment); } node2Fragment(el) { let fragment = document.createDocumentFragment(), child; // copy the original node to fragment while (child = el.firstChild) {// appendChild moves the element up from dom to fragment fragment.appendChild(child); } return fragment; } compileElement(el) { let childNodes = el.childNodes; [].slice.call(childNodes).forEach(node => { let text = node.textContent; let reg = /\{\{(.*)\}\}/; if (this.isElementNode(node)) { this.compile(node); } else if (this.isTextNode(node) && reg.test(text)) { this.compileText(node, RegExp.$1); } if (node.childNodes && node.childNodes.length) { this.compileElement(node); }}}})Copy the code
Among them
While (child = el.firstChild) {// appendChild moves the element up from dom to fragment fragment.appendChild(child); }Copy the code
AppendChild changes the original DOM structure by gradually moving DOM element nodes into fragments.
The complete code
Vue source
conclusion
The data-flow-oriented MVVM mode greatly simplifies front-end operations on DOM, speeds up front-end development, and improves user experience.
Reference:
Analysis of Vue principle & Realization of bidirectional binding MVVM MVVM Liao Xuefeng