Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of two-way binding in Front-end MVVM Framework

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces the example analysis of two-way binding in the front-end MVVM framework, which has a certain reference value, and interested friends can refer to it. I hope you will gain a lot after reading this article.

Basic concepts of MVVM framework

In the MVVM framework, View (view) and Model (data) cannot communicate directly, and there is an intermediary between them, ViewModel, which acts as an observer. When the user manipulates the View (view), the ViewModel senses the change and then notifies the Model of the corresponding change; on the contrary, when the Model (data) changes, the ViewModel can also perceive the change and make the View update accordingly. This round-trip process is known as two-way binding.

Application scenario of MVVM Framework

The benefits of the MVVM framework are obvious: when the current side operates on the data, the data can be persisted through Ajax requests, only by changing the part of the data in the dom that needs to be changed, without having to refresh the entire page. Especially on the mobile side, refreshing pages is too expensive. Although some resources will be cached, the dom, css and js of the page will be reparsed by the browser, so the mobile page will usually be made into a SPA single-page application. On this basis, many MVVM frameworks are born, such as React.js, Vue.js, Angular.js and so on.

Simple implementation of MVVM Framework

Simulate the bi-directional binding flow of Vue and implement a simple MVVM framework. From the above figure, you can see that the dotted square is the previously mentioned ViewModel intermediary layer, which acts as an observer. In addition, it can be found that View to Model in a two-way binding flow is actually implemented through the event listening function of input. If it is replaced by React (one-way binding flow), it is implemented by a state management tool (such as Redux) at this step. In addition, the implementation of Model to View in two-way binding flow is more or less the same, and the core method used is Object.defineProperty (), through which data hijacking can be carried out, and the corresponding changes can be captured when the data changes, so as to carry out subsequent processing.

Implementation of Mvvm (entry file)

The Mvvm framework is usually called like this

Const vm = new Mvvm ({el:'# app', data: {title: 'mvvm title', name:' mvvm name'},})

But in this case, if you want to get the title attribute, you have to get it like vm.data.title, so that vm.title can get the title attribute, thus adding a proxy method to the prototype of Mvvm, as follows:

Function Mvvm (options) {this.data = options.data const self = this Object.keys (this.data) .forEach (key = > self.proxyKeys (key))} Mvvm.prototype = {proxyKeys: function (key) {const self = this Object.defineProperty (this, key, {get: function () {/ / get and set realize the synchronization of vm.data.title and vm.title values return self.data [key]} Set: function (newValue) {self.data [key] = newValue}})}

After realizing the agent method, we will step into the implementation of the main process.

Function Mvvm (options) {this.data = options.data / /... Observe (this.data) new Compile (options.el, this)}

Implementation of observer (Observer)

Observer is responsible for listening for changes in Model (JS object). The core part is to use the get and set methods of Object.defineProperty (). When you want to get the value of Model (JS object), the get method is automatically called; when the value of Model (JS object) is changed, the set method is automatically called; thus the data hijacking is realized, as shown below.

Let data = {number: 0} observe (data) data.number = 1 / / value changes function observe (data) {if (! data | | typeof (data)! = = 'object') {return} const self = this Object.keys (data) .forEach (key = > self.defineReactive (data, key, data [key]))} function defineReactive (data, key, value) {observe (value) / / traverses nested objects Object.defineProperty (data, key) {get: function () {return value}, set: function (newValue) {if (value! = = newValue) {console.log ('value change', 'newValue:' + newValue +' + 'oldValue:' + value) value = newValue}})})}

By running the code, you can see that the output value of the console has changed, newValue:1 oldValue:0, and the logic of observer is complete.

The relationship between Dep (array of subscribers) and watcher (subscribers)

After observing a change, we should always inform a specific group of people and let them deal with it accordingly. To make it easier to understand, we can think of a subscription as a Wechat official account. When the content of the Wechat official account is updated, it will update the content to the people who subscribe to it.

So there are thousands of people who subscribe to the same Wechat official account, so the first thing that comes to mind is to new Array () to store these people (html node). So you have the following code:

/ / observer.jsfunction Dep () {this.subs = [] / / Storage subscriber} Dep.prototype = {addSub: function (sub) {/ / add subscriber this.subs.push (sub)}, notify: function () {/ / notify subscriber to update this.subs.forEach (function (sub) {sub.update ()}} function observe (data) {.} function defineReactive (data, key) Value) {var dep = new Dep () observe (value) / / traverse nested objects Object.defineProperty (data, key, {get: function () {if (Dep.target) {/ / add subscriber dep.addSub (Dep.target)} return value}, set: function (newValue) {if (value! = newValue) {console.log ('value changed') 'newValue:' + newValue +' + 'oldValue:' + value) value = newValue dep.notify ()})}

At first glance, the code is smoother, but it may get stuck in Dep.target and sub.update, so it's natural to turn your attention to watcher.

/ watcher.jsfunction Watcher (vm, exp, cb) {this.vm = vm this.exp = exp this.cb = cb this.value = this.get ()} Watcher.prototype = {update: function () {this.run ()}, run: function () {/ /. If (value! = = oldVal) {this.cb.call (this.vm, value) / / trigger callback in compile}}, get: function () {Dep.target = this / / cache yourself const value = this.vm.data [this.exp] / / enforce the get function in the listener Dep.target = null / / release return value}

You can see from the code that the get () method is called when the Watcher instance is constructed, and then focus on the sentence const value = this.vm.data [this.exp]. As mentioned earlier, when you want to get the value of Model (JS object), the get method of Object.defineProperty is automatically called, that is, when this sentence is executed, the value of Dep.target is passed into the get method of Object.defineProperty in observer.js. At the same time, the update method is clearly found in Watcher.prototype, which triggers a callback bound in compile to update the interface. So far, it explains the origin of Dep.target and sub.update in Observer.

To sum up the role of Watcher, which acts as a bridge between observer and compile.

1 in the process of self-instantiation, add yourself to the dep

2 when model changes and dep.notify () notifies it, it can call its own update function and trigger the callback function bound by compile to update the view.

Finally, let's take a look at the compile.js file that generated the Watcher instance.

Implementation of compile (compilation)

First of all, the process of traversing and parsing involves multiple operations on the dom node. In order to improve performance and efficiency, the el of the following node will be converted into fragment (document fragments) for parsing and compilation, parsing is completed, and then fragment will be added back to the original real dom node. The code is as follows:

Function Compile (el, vm) {this.vm = vm this.el = document.querySelector (el) this.fragment = null this.init ()} Compile.prototype = {init: function () {if (this.el) {this.fragment = this.nodeToFragment (this.el) / / convert nodes to fragment document fragments this.compileElement (this.fragment) / / one pair of fragment compiles and parses this.el.appendChild (this.fragment)}} NodeToFragment: function (el) {const fragment = document.createDocumentFragment () let child = el.firstChild / / △ the first firstChild is text while (child) {fragment.appendChild (child) child = el.firstChild} return fragment}, compileElement: function (el) {...},}

This simple mvvm framework deals with {{}} text elements, v-on:click event instructions and v-model instructions in the process of compiling and parsing fragment.

Compile.prototype = {init: function () {if (this.el) {this.fragment = this.nodeToFragment (this.el) / / convert nodes to fragment document fragments this.compileElement (this.fragment) / / A pair of fragment is compiled and parsed this.el.appendChild (this.fragment)}}, nodeToFragment: function (el) {...}, compileElement: function (el) {...}, compileText: function (node) Exp) {/ / A pair of text types are processed Replace {{abc}} with const self = this const initText = this.vm [exp] this.updateText (node, initText) / / initialize new Watcher (this.vm, exp, function (value) {/ / instantiate subscriber self.updateText (node, value)}, compileEvent: function (node, vm, exp) Dir) {/ / one pair of event instructions for processing const eventType = dir.split (':') [1] const cb = vm.methods & & vm.methods [exp] if (eventType & & cb) {node.addEventListener (eventType, cb.bind (vm), false)}}, compileModel: function (node, vm, exp) {/ / one pair of v-model for processing let val = vm [exp] const self = this this.modelUpdater (node, val) node.addEventListener ('input') Function (e) {const newValue = e.target.value self.vm [exp] = newValue / / implement the binding of view to model})}, thank you for reading this article carefully I hope the article "sample Analysis of two-way binding in the Front-end MVVM Framework" shared by the editor will be helpful to you. At the same time, I also hope that you will support and pay attention to the industry information channel. More related knowledge is waiting for you to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report