search
HomeWeb Front-endJS TutorialOnly 30 lines of code to implement MVC_javascript techniques in Javascript

Since around 2009, MVC has gradually shined in the front-end field, and finally ushered in a big explosion with the launch of React Native in 2015: AngularJS, EmberJS, Backbone, ReactJS, RiotJS, VueJS... ... A series of names have appeared and changed in a flashy way. Some of them have gradually faded out of everyone's sight, some are still growing rapidly, and some have already taken on their own role in a specific ecological environment. But no matter what, MVC has and will continue to profoundly affect the way of thinking and working methods of front-end engineers.

Many examples of explaining MVC start from a certain concept of a specific framework, such as Backbone's collection or the model in AngularJS. This is certainly a good approach. But the reason why a framework is a framework, not a class library (jQuery) or a tool set (Underscore), is because there are many excellent design concepts and best practices behind them. These design essences complement each other, are interlocked, and are indispensable. , it is not easy to see the essence of a certain design pattern through a complex framework in a short period of time.

This is the origin of this essay - the prototype code created to help everyone understand the concept should be as simple as possible, just simple enough for everyone to understand the concept.

1. The basis of MVC is the observer pattern, which is the key to achieving synchronization between model and view
For simplicity, each model instance contains only one primitive value.

function Model(value) {
  this._value = typeof value === 'undefined' ? '' : value;
  this._listeners = [];
}
Model.prototype.set = function (value) {
  var self = this;
  self._value = value;
  // model中的值改变时,应通知注册过的回调函数
  // 按照Javascript事件处理的一般机制,我们异步地调用回调函数
  // 如果觉得setTimeout影响性能,也可以采用requestAnimationFrame
  setTimeout(function () {
    self._listeners.forEach(function (listener) {
      listener.call(self, value);
    });
  });
};
Model.prototype.watch = function (listener) {
  // 注册监听的回调函数
  this._listeners.push(listener);
};
// html代码:
<div id="div1"></div>
// 逻辑代码:
(function () {
  var model = new Model();
  var div1 = document.getElementById('div1');
  model.watch(function (value) {
    div1.innerHTML = value;
  });
  model.set('hello, this is a div');
})();

With the help of the observer pattern, we have realized that when the set method of the model is called to change its value, the template is also updated synchronously, but this implementation is very awkward because we need to manually monitor the change of the model value (through the watch method ) and pass in a callback function. Is there a way to make it easier to bind the view (one or more dom nodes) to the model?

2. Implement the bind method and bind the model and view

Model.prototype.bind = function (node) {
  // 将watch的逻辑和通用的回调函数放到这里
  this.watch(function (value) {
    node.innerHTML = value;
  });
};
// html代码:
<div id="div1"></div>
<div id="div2"></div>
// 逻辑代码:
(function () {
  var model = new Model();
  model.bind(document.getElementById('div1'));
  model.bind(document.getElementById('div2'));
  model.set('this is a div');
})();

Through a simple encapsulation, the binding between view and model has taken shape. Even if multiple views need to be bound, it is easy to implement. Note that bind is a native method on the Function class prototype, but it is not closely related to MVC. The author really likes the word bind. It is to the point and concise, so I simply cover the native method here. You can neglect. Closer to home, although the complexity of binding has been reduced, this step still requires us to complete it manually. Is it possible to completely decouple the binding logic from the business code?

3. Implement controller to decouple binding from logic code

Careful friends may have noticed that although we are talking about MVC, only the Model class appears in the above article. It is understandable that the View class does not appear. After all, HTML is a ready-made View (in fact, this article also mentions it from beginning to end. Just using HTML as View, the View class does not appear in the javascript code), then why is the Controller class invisible? Don't worry, in fact, the so-called "logic code" is a code segment with a high degree of coupling between framework logic (let's call this article's prototype toy a framework) and business logic. Let's break it down now.
If you want to leave the binding logic to the framework, you need to tell the framework how to complete the binding. Since it is difficult to complete annotation in JS, we can do this layer of markup in the view - using the tag attribute of html is a simple and effective way.

function Controller(callback) {
  var models = {};
  // 找到所有有bind属性的元素
  var views = document.querySelectorAll('[bind]');
  // 将views处理为普通数组
  views = Array.prototype.slice.call(views, 0);
  views.forEach(function (view) {
    var modelName = view.getAttribute('bind');
    // 取出或新建该元素所绑定的model
    models[modelName] = models[modelName] || new Model();
    // 完成该元素和指定model的绑定
    models[modelName].bind(view);
  });
  // 调用controller的具体逻辑,将models传入,方便业务处理
  callback.call(this, models);
}




// html:
<div id="div1" bind="model1"></div>
<div id="div2" bind="model1"></div>
// 逻辑代码:
new Controller(function (models) {
  var model1 = models.model1;
  model1.set('this is a div');
});


Is it that simple? It's that simple. The essence of MVC is to complete business logic in the controller and modify the model. At the same time, changes in the model cause automatic updates of the view. These logics are reflected in the above code and support multiple views and multiple models. Although it is not enough for production projects, I hope it will be somewhat helpful to everyone's MVC learning.

The organized "framework" code with comments removed:

function Model(value) {
  this._value = typeof value === 'undefined' &#63; '' : value;
  this._listeners = [];
}
Model.prototype.set = function (value) {
  var self = this;
  self._value = value;
  setTimeout(function () {
    self._listeners.forEach(function (listener) {
      listener.call(self, value);
    });
  });
};
Model.prototype.watch = function (listener) {
  this._listeners.push(listener);
};
Model.prototype.bind = function (node) {
  this.watch(function (value) {
    node.innerHTML = value;
  });
};
function Controller(callback) {
  var models = {};
  var views = Array.prototype.slice.call(document.querySelectorAll('[bind]'), 0);
  views.forEach(function (view) {
    var modelName = view.getAttribute('bind');
    models[modelName] = models[modelName] || new Model();
    models[modelName].bind(view);
  });
  callback.call(this, models);
}

Postscript:

In the process of learning flux and redux, although the author has mastered how to use the tools, I only know it but don’t know why. I have always emphasized "Flux eschews MVC in favor of a unidirectional data flow" in the official ReactJS documentation. I don’t quite understand. I always feel that one-way data flow and MVC do not conflict. I don’t understand why the two are opposed in the ReactJS document. There is one without me, there is one without him (eschew, avoid). Finally, I made up my mind to go back to the definition of MVC and study it again. Although I copy and paste carelessly in my daily work, we still have to be willful and chew on the words occasionally, right? This method really helped me understand this sentence. Here I can share my thoughts with you: The reason why I feel that the one-way data flow in MVC and flux is similar may be because there is no clear distinction between MVC and the observer pattern. Caused by the relationship - MVC is based on the observer pattern, and so is flux, so the source of this similarity is the observer pattern, not MVC and flux themselves. This understanding is also confirmed in the original design pattern book of the foursome: "The first and perhaps best-known example of the Observer pattern appears in Smalltalk Model/View/Controller (MVC), the user interface framework in the Smalltalk environment [KP88]. MVC's Model class plays the role of Subject, while View is the base class for observers. ".

If readers are interested in continuing to expand on such a prototype toy, you can refer to the following directions:

  • 1. Implement two-way binding of input class tags
  • 2. Achieve precise control of the scope controlled by the controller. Here one controller controls the entire DOM tree
  • 3. Implement the logic of hiding/showing, creating/destroying dom nodes in the view layer
  • 4. Integrate virtual dom, add dom diff function, and improve rendering efficiency
  • 5. Provide dependency injection function to achieve inversion of control
  • 6. Perform security checks on the assignment content of innerHTML to prevent malicious injection
  • 7. Implement the logic of model collection, where each model has only one value
  • 8. Use the setter in es5 to change the implementation of the set method, making it easier to modify the model
  • 9. Add control over attributes and css in the view layer
  • 10. Supports syntax similar to double braces in AngularJS, binding only part of html
  • ……

A complete framework needs to go through countless refinements and modifications. This is just the first step. The road is still long. I hope everyone will continue to work hard.

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Atom editor mac version download

Atom editor mac version download

The most popular open source editor