directory
What is MVC?
MVC functions:
How to use the MVC architecture:
Effect:
Here is all the code:
Source address: https://gitee.com/DieHunter/myCode/tree/master/shopCarMVC
Back-end (nodejs) :
server.js
Data.js (store list of items)
The front end
Shopcar.html (entry page)
shop.css
JS folder:
bussiness
command
components
config
controller
event
model
utils
view
conclusion
What is MVC?
Model View Controller: Model-view-controller Generally speaking, in programming languages, Model is data, which can be understood as a database, View is the appearance of data, Controller is used to connect the behavior of the first two, common Vue adopts m-V-VM architecture, similar to MVC, but based on MVC
MVC functions:
When it comes to functions, there is a distinction between object orientation and process orientation
Process oriented is the process of solving a problem step by step, closely linked together to achieve the final result
Object oriented, is the solution of a problem is stripped away, its purpose is not to complete a step, but a thing (object) role (attribute) and behavior (method) as the core
Having said that, what’s so good about MVC?
Here’s an example: A is A front-end programmer in A company, usually with A process oriented programming, this day, very not easy to complete his hand over the heads of the living, ready to go home, at this time, the product manager came and let him change A small place, it is finished, interlocking process oriented thinking makes his code, the code coupling is strong, high cohesion, inseparable, change A place will be almost entirely
A’s brother is also A front-end programmer who usually uses object-oriented programming, but the product manager asked him to change an effect. Because he uses object-oriented programming, his code has no sense of hierarchy, and all general methods are extracted, which makes the code coupling low. If he wants to change, he can directly change related classes or methods
Of course, it can not reflect its advantages in small projects, and even make a mountain out of a molehill, overuse, and in large projects, its coupling is low, code reuse is high, build relatively fast
How to use the MVC architecture:
In my spare time, I made a simple shopping cart with MVC:
The directory structure looks something like this
Overall process of shopping cart:
The directory structure strips the Model View Controller away
Modedl layer: Stores and displays data
View: Render the page based on Model data
Controller: transfers data
Command: Operates data and obtains data
Event: Event bus, registering events
List of products:
Initialize the View layer, set up Ajax to fetch data, and then the Controller triggers events to the event bus, and then the registered events pass Ajax data to the Model to complete the initialization of the list of goods
When Model gets the commodity list data, the event of creating a commodity list is triggered by the agent set(), and the purpose of creating a list is achieved by the command operation view
Shopping cart Form:
When the user operates on the view, the registered event is triggered, and the data in the Model (the shopping cart list) is modified by Command, which in turn drives the refresh table in the View for rendering
Effect:
Here is all the code:
Source code address:Gitee.com/DieHunter/m…
Back-end (nodejs) :
server.js
/* * Back end uses Node + Express to build a simple interface, through local data, the list of goods to the front end * */
const express = require('express');
const path = require('path');
const app = express();
const shopData = require('./data/shopData.js')
let serverToken = 'hello'
app.all("*".function (req, res, next) { / / across domains
res.header("Access-Control-Allow-Origin"."*");
res.header("Access-Control-Allow-Headers"."content-type");
res.header("Access-Control-Allow-Methods"."DELETE,PUT,POST,GET,OPTIONS");
next();
});
app.use('/getShopList'.function (req, res) {
let data = req.query
if(! checkToken(data.token)) {// Simply obtain front-end token and verify
res.send({
result: 0.msg: 'token fail'
})
return
}
res.send({
result: 1.msg: 'success'.type: 'getShopList',
shopData
})
})
function checkToken(teken) {
return teken == serverToken
}
app.use('/img', express.static(path.join(__dirname, './img'))); // Use url+img to access the folder
app.use('/client', express.static(path.join(__dirname, '.. /client')));
app.listen(1024."127.0.0.1".function () {
console.log("Service started, listening");
});
Copy the code
Data.js (store list of items)
module.exports = [{
"select": false."id": 1001."icon": "img/1.png"."name": 0 "restaurant"."num": 0."price": 10."sum": 0."delete": false
},
{
"select": false."id": 1002."icon": "img/2.png"."name": 1 "restaurant"."num": 0."price": 20."sum": 0."delete": false
},
{
"select": false."id": 1003."icon": "img/3.png"."name": 2 "the restaurant"."num": 0."price": 30."sum": 0."delete": false
},
{
"select": false."id": 1004."icon": "img/4.png"."name": 3 "restaurant"."num": 0."price": 40."sum": 0."delete": false
},
{
"select": false."id": 1005."icon": "img/5.png"."name": 4 "restaurant"."num": 0."price": 50."sum": 0."delete": false
},
{
"select": false."id": 1006."icon": "img/6.png"."name": 5 "restaurant"."num": 0."price": 60."sum": 0."delete": false
},
{
"select": false."id": 1007."icon": "img/7.png"."name": 6 "restaurant"."num": 0."price": 70."sum": 0."delete": false
},
{
"select": false."id": 1008."icon": "img/8.png"."name": 7 "restaurant"."num": 0."price": 80."sum": 0."delete": false
},
{
"select": false."id": 1009."icon": "img/9.png"."name": 8 "restaurant"."num": 0."price": 90."sum": 0."delete": false
},
{
"select": false."id": 1010."icon": "img/10.png"."name": 9 "restaurant"."num": 0."price": 100."sum": 0."delete": false}]Copy the code
The front end
Shopcar.html (entry page)
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>shopCar</title>
<link rel="stylesheet" href="./src/style/shop.css">
</head>
<body>
<script type="module">
View: render the page according to the model data. Controller: pass the data. Command: manipulate the data. Event bus, register event commodity list: Initialize the View layer, set up Ajax to fetch data, and then trigger events to the event bus from the Controller, and then pass Ajax data to the Model from the registered event to complete the item list initialization. When the Model gets the item list data, the new item list event is triggered by the agent set(). When the user manipulates the view, the registration event is triggered, and the data in the Model (the shopping cart list) is modified by Command, which then drives the refresh table in the view to render */
import ShopView from './src/js/view/ShopView.js'
// Instantiate the View layer entry function
new ShopView()
</script>
</body>
</html>
Copy the code
shop.css
* {
margin: 0;
padding: 0;
}
.shopBox {
overflow: hidden;
width: 1000px;
margin: 50px auto 0;
}
.liItem {
float: left;
list-style: none;
padding: 10px;
width: 150px;
height: 200px;
text-align: center;
border: 1px solid lightcoral;
}
.liItem img {
width: 100px;
height: 100px;
}
.leftBtn..rightBtn {
width: 30px;
height: 30px;
background: white;
border: 1px solid black;
font-size: 25px;
line-height: 30px;
}
.text {
width: 50px;
height: 26px;
display: inline-block;
vertical-align: bottom;
text-align: center;
}
table {
font-size: 30px;
width: 1200px;
border: 1px solid lightcoral;
border-collapse: collapse;
margin: 50px auto;
}
.checkbox {
width: 30px;
height: 30px;
}
td {
border: 1px solid lightcoral;
text-align: center;
vertical-align: middle;
}
td button {
width: 150px;
height: 60px;
}
.numBox {
width: 150px;
height: 30px;
margin: auto;
position: relative;
}
.numBox>button {
width: 40px;
height: 42px;
background-color: white;
border: 1px solid # 000000;
}
.numBox>input {
width: 70px;
height: 40px;
border: 1px solid # 000000;
border-left: none;
border-right: none;
text-align: center;
}
Copy the code
JS folder:
bussiness
-
Ajax.js
import ShopEvent from '.. /event/ShopEvent.js' import Utils from '.. /utils/Utils.js' import Api from '.. /config/Api.js' import ShopController from '.. /controller/ShopController.js' export default class Ajax {//Ajax class for requesting backend or local data // Ajax request function static AjaxTool(method = Api.GET, url, data) { let xhr; if (window.ActiveXObject) { / / ie browser xhr = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { // Other browsers xhr = new XMLHttpRequest(); } url = Api.URL + Api.PORT + Api.PATH + url if(method ! == Api.POST) { method = Api.GET url = Utils.urlJoin(url, data) data =null } else { method = Api.POST } xhr.open(method, url); xhr.send(data ? JSON.stringify(data) : ' ') xhr.addEventListener('load', Ajax.loadHandler) // The Ajax class is static and cannot use this } static loadHandler(e) { / / this point to XHR let xhr = e.currentTarget; if (xhr.readyState === 4 && xhr.status === 200) { Ajax.data = xhr.response } else { Ajax.data = 'error'}}static set data(value) { // Use the set object proxy mode instead of the request data callback function. let res = JSON.parse(value) switch (res.result) { case 1: console.log(res.msg) ShopController.dispatch(ShopEvent.GET_DATA, res)// Get the data and do nothing else. Throw the data into the Event bus through the Event bus break; case 0: console.log('Load failed') console.log(res.msg) break; default: break; }}}Copy the code
command
-
MainCommand (Command summary)
import GetDataCommand from '.. /command/GetDataCommand.js' import CreateListCommand from '.. /command/CreateListCommand.js' import CreateTableCommand from '.. /command/CreateTableCommand.js' import AddItemCommand from '.. /command/AddItemCommand.js' import DelItemCommand from '.. /command/DelItemCommand.js' import ReduceItemCommand from '.. /command/ReduceItemCommand.js' import ChangeItemCommand from '.. /command/ChangeItemCommand.js' import SelectItemCommand from '.. /command/SelectItemCommand.js' export default { GetDataCommand, CreateListCommand, CreateTableCommand, AddItemCommand, DelItemCommand, ReduceItemCommand, ChangeItemCommand, SelectItemCommand } Copy the code
-
GetDataCommand (Get a list of items)
import ShopModel from '.. /model/ShopModel.js' export default class GetDataCommand { // Action class for executing commands sent by the CTRL layer through events constructor(){}eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e ShopModel.getInstance().shopList = data.shopData// Send the ajax-fetched data to Model}}Copy the code
-
CreateListCommand (Create a list of items)
import CreateList from '.. /view/CreateList.js' export default class CreateListCommand { // Action class for executing commands sent by the CTRL layer through events constructor() {// Create a list of items } eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e for (let i = 0; i < data.length; i++) { let createList = new CreateList(document.body) createList.shopList = data[i] } } } Copy the code
-
CreateTableCommand Create shopping cart table
import CreateTable from '.. /view/CreateTable.js' export default class ShopCommand { // Action class for executing commands sent by the CTRL layer through events constructor() {// Refresh the cart table } eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e let createTable = new CreateTable(document.body) createTable.shoppingList = data } } Copy the code
-
AddItemCommand (add items)
import ShopModel from '.. /model/ShopModel.js' export default class AddItemCommand { // Action class for executing commands sent by the CTRL layer through events constructor() { // Add new items } eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e AddItemCommand.addItem(ShopModel.getInstance().shoppingList, data) } static addItem(list, data) { // iterate to query for an item increase or decrease let arr = list.filter(function (item) { return item.id === data.id; }); // If there is a return value, the item is operated on (between 1 and 99, if 0, delete directly). if (arr.length == 0) { data.num++; data.sum = data.num * data.price; list.push(data); } else if (arr[0].num < 99) { arr[0].num++; arr[0].sum = arr[0].num * arr[0].price; } ShopModel.getInstance().shoppingList = list } } Copy the code
-
ReduceItemCommand (Reduce items)
import ShopModel from '.. /model/ShopModel.js' export default class ReduceItemCommand { // Action class for executing commands sent by the CTRL layer through events constructor() { // Reduce items } eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e ReduceItemCommand.reduceItem(ShopModel.getInstance().shoppingList, data) } static reduceItem(list, data) { // iterate to query for an item increase or decrease let arr = list.filter(function (item) { return item.id === data.id; }); // If there is a return value, the item is operated on (between 1 and 99, if 0, delete directly). if (arr[0].num > 1) { arr[0].num--; arr[0].sum = arr[0].num * arr[0].price; } else { data.num = 0; // Initialize shopList in model here, otherwise fake delete (delete stack quantity) list = list.filter(function (item) { returnitem.id ! == data.id; }); } ShopModel.getInstance().shoppingList = list } }Copy the code
-
ChangeItemCommand (Modifies the number of items)
import ShopModel from '.. /model/ShopModel.js' export default class ChangeItemCommand { // Action class for executing commands sent by the CTRL layer through events constructor() { // Change the number of items } eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e ChangeItemCommand.changeItem(ShopModel.getInstance().shoppingList, data) } static changeItem(list, data) { let arr = list.filter(function (item) { return item.id === data.id; }); arr[0].sum = arr[0].num * arr[0].price; ShopModel.getInstance().shoppingList = list } } Copy the code
-
DelItemCommand (delete an item)
import ShopModel from '.. /model/ShopModel.js' export default class DelItemCommand { // Action class for executing commands sent by the CTRL layer through events constructor() { // Delete the item } eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e DelItemCommand.delItem(ShopModel.getInstance().shoppingList, data) } static delItem(list, data) { // iterate to query for an item increase or decrease data.num = 0; // Initialize shopList in model here, otherwise fake delete (delete stack quantity) data.select = false; // Initialize shopList in model here, otherwise fake delete (delete stack quantity) ShopModel.getInstance().shoppingList = list.filter(function (item) { // Array filter function, return the array whose ID attribute is not equal to the current ID, that is, delete the currently selected object, and reassign the value return item.id !== data.id; }); } } Copy the code
-
SelectItemCommand
import ShopModel from '.. /model/ShopModel.js' export default class SelectItemCommand { // Action class for executing commands sent by the CTRL layer through events constructor(){}eventHandler(e) { // Use dynamic methods instead of static static methods, because the method will be used multiple times, instantiated with new AddShopCommand and called let { data } = e SelectItemCommand.selItem(ShopModel.getInstance().shoppingList, data) } static selItem(list, data) { // iterate to query for an item increase or decrease if(! data) {/ / the marqueelist.checkedAll = ! list.checkedAll list.map(function (item) { item.select = list.checkedAll; // Other option boxes are in the same state as the full option boxes})}else { / / radio buttons list.checkedAll = 1 // counter is used to check whether all is selected list.map(function (item) { // select one of the tables (checkAll is executed when the table is initialized) if(item.id === data.id) { item.select = ! item.select } list.checkedAll *= item.select }) } ShopModel.getInstance().shoppingList = list } }Copy the code
components
-
Counter (Counter component)
import ShopEvent from '.. /event/ShopEvent.js' import ShopController from '.. /controller/ShopController.js' import Utils from '.. /utils/Utils.js' export default class Counter { // Counter component constructor(_data, _parentEle) { this.data = _data this.parentEle = _parentEle this.ele = this.createCounter() } createCounter() { // Create a quantity counter let div = Utils.createEle('div', {}, { className: 'numBox' }) this.parentEle.appendChild(div); let leftBtn = this.createMark(div, 'reduce') // Reduce the merchandise button let input = Utils.createEle('input', {}, { type: 'text'.value: this.data.num }) div.appendChild(input); let rightBtn = this.createMark(div, 'add') // Add product button leftBtn.addEventListener("click".this.reduceItemEvent); rightBtn.addEventListener("click".this.addItemEvent); input.addEventListener("input", Utils.throttle(this.changeItemEvent, 500)); / / throttling return div; } createMark(parentEle, type) { // Determine whether to increase or decrease keys let markBtn = Utils.createEle('button', {}, { textContent: type == "add" ? '+' : The '-' }) parentEle.appendChild(markBtn); return markBtn } addItemEvent = e= > { // When a new item is added, an event is thrown to the command control model to modify the data and refresh the table ShopController.dispatch(ShopEvent.ADD_SHOPIING_ITEM, this.data) } reduceItemEvent = e= > { // Reduce items ShopController.dispatch(ShopEvent.REDUCE_SHOPIING_ITEM, this.data) } changeItemEvent = e= > { // Modify the item e.target.value = this.data.num = this.checkNumber(e.target.value) ShopController.dispatch(ShopEvent.CHANGE_SHOPIING_ITEM, this.data) } checkNumber(value) { // Filter data value = value.replace(/[^0-9]/g.""); // Only numbers are allowed if (value === "0") { // If =0, set to 1 value = "1"; } if (value.length > 2) { // If the input is more than 2 bits, make the value 99 (Max. 99 bits) value = "99"; } if (value.length === 0) { // If there is no input, set it to 1 value = "1"; } return value } } Copy the code
config
-
Api
export default class Api {// Interface configuration class static URL = "http://127.0.0.1"; static PORT = ": 1024"; static PATH = '/' static GET = "get"; static POST = "post"; static IMGPATH = Api.URL + Api.PORT + Api.PATH; static ServerApi = { getShopList: 'getShopList' // Get the list of items}}Copy the code
controller
-
ShopController (control layer, do event conduction, data transmission)
export default class ShopController extends EventTarget { // The control layer handles user interaction, routing, and input. The model View Controller is stripped away, and the data is routed through the event listener cast in the Controller constructor() { // Inherits the event object, which is used to throw custom events super(a); }static get instance() { / / singleton written with Java getinstance similar, new generates a new object, memory, and so to write can give you an existing reference use, save effectiveness, if only use the get + property name instead of a read-only property set, only allow calls, cannot be modified if(! ShopController._instance) {Object.defineProperty(ShopController, "_instance", { value: new ShopController() }) } return ShopController._instance; } static dispatch(type, data) { // Throw a defined event to pass data let event = new Event(type) event.data = data ShopController.instance.dispatchEvent(event) } static runCommand(type, Command) { // Observer mode, which calls a method in another class when a custom event is triggered, corresponds to Dispatch, similar to addEventlistener, but replaces the callback function with a dynamic method in the class var command = new Command() ShopController.instance.addEventListener(type, command.eventHandler) } } Copy the code
event
-
ShopEvent
export default class ShopEvent { constructor(){}// All custom event names static GET_DATA = 'get_data' static GET_SHOP_LIST = 'get_shop_list' static GET_SHOPIING_LIST = 'get_shopping_list' static ADD_SHOPIING_ITEM = 'add_shopping_item' static DEL_SHOPIING_ITEM = 'del_shopping_item' static REDUCE_SHOPIING_ITEM = 'reduce_shopping_item' static CHANGE_SHOPIING_ITEM = 'change_shopping_item' static SELECT_SHOPIING_ITEM = 'select_shopping_item' } Copy the code
-
EventGroup (Event Bus)
import ShopEvent from './ShopEvent.js' import ShopController from '.. /controller/ShopController.js' import MainCommand from '.. /command/MainCommand.js' let { GetDataCommand, CreateListCommand, CreateTableCommand, AddItemCommand, DelItemCommand, ReduceItemCommand, ChangeItemCommand, SelectItemCommand } = MainCommand export default class EventGroup { // The event bus, which registers all the business logic of the Model layer and other layers, communicates through the event mechanism in the Controller layer constructor() { /* 1. After Ajax gets the data, the method in GetDataCommand is triggered to pass the data to the Model layer, and CreateListCommand is called from the Model layer to create item list 2. CreateTableCommand 3 is triggered by any action the user makes to the item, which modifies the Model to trigger CreateTableCommand. CreateTableCommand 4 is driven by AddItemCommand, which is triggered when the list of items is clicked or the plus button is clicked. AddItemCommand modifies the data in the Model using AddItemCommand. Click the item minus button and trigger the ReduceItemCommand to modify the data in the Model to drive CreateTableCommand 5. CreateTableCommand 6 is driven by DelItemCommand when the Delete item button is clicked, which deletes the data in the Model. CreateTableCommand 7 is driven by the ChangeItemCommand that is triggered when the number of items is changed, updating the data in the Model. SelectItemCommand is triggered when an item is selected, updating the data in the model to drive CreateTableCommand */ ShopController.runCommand(ShopEvent.GET_DATA, GetDataCommand)// Get item list data ShopController.runCommand(ShopEvent.GET_SHOP_LIST, CreateListCommand)// Create an item list ShopController.runCommand(ShopEvent.GET_SHOPIING_LIST, CreateTableCommand)// Refresh the cart table ShopController.runCommand(ShopEvent.ADD_SHOPIING_ITEM, AddItemCommand)// Add item or quantity plus one ShopController.runCommand(ShopEvent.DEL_SHOPIING_ITEM, DelItemCommand)// Delete the item ShopController.runCommand(ShopEvent.REDUCE_SHOPIING_ITEM, ReduceItemCommand)// Quantity of goods minus 1 ShopController.runCommand(ShopEvent.CHANGE_SHOPIING_ITEM, ChangeItemCommand)// Change the number of items ShopController.runCommand(ShopEvent.SELECT_SHOPIING_ITEM, SelectItemCommand)// Select the item}}Copy the code
model
-
ShopModel (Model layer for data storage and data logic)
import ShopEvent from '.. /event/ShopEvent.js' import ShopController from '.. /controller/ShopController.js' export default class ShopModel { // The model layer is used for data storage and data logic. The data is passed through the event handling mechanism (controller), and the data is manipulated by the command constructor() { this._shopList = null this._shoppingList = [] } static getInstance() { / / singleton written with Java getinstance similar, new generates a new object, memory, and so to write can give you an existing reference use, save effectiveness, if only use the get + property name instead of a read-only property set, only allow calls, cannot be modified if(! ShopModel._instance) {Object.defineProperty(ShopModel, "_instance", { value: new ShopModel() }) } return ShopModel._instance; } set shopList(value) {// Set the list of items this._shopList = value; ShopController.dispatch(ShopEvent.GET_SHOP_LIST, value) } get shopList() { return this._shopList } set shoppingList(value) {// When data is modified, drive the view to refresh the table this._shoppingList = value; ShopController.dispatch(ShopEvent.GET_SHOPIING_LIST, value) } get shoppingList() { return this._shoppingList } } Copy the code
utils
-
Utils (Utility classes)
export default class Utils { / / tools // Concatenate the object into the URL static urlJoin(url, obj) { var list = [] for (var key in obj) { if (obj.hasOwnProperty(key)) { list.push(`${key}=${obj[key]}`)}}return `${url}?${list.join('&')}` } static createEle(ele, style, attribute) { // Add tags, set attributes and styles let element = document.createElement(ele) if (style) { for (let key instyle) { element.style[key] = style[key]; }}if (attribute) { for (let key inattribute) { element[key] = attribute[key]; }}return element } // function throttling static throttle(fn, time) { let _timer = null return function () { if (_timer) { clearTimeout(_timer) _timer = null } _timer = setTimeout(fn.bind(this. arguments), time) } } }Copy the code
view
-
ShopView (View layer, for element rendering, displaying data)
import Api from '.. /config/Api.js' import AJAX from '.. /bussiness/Ajax.js' import EventGroup from '.. /event/EventGroup.js' export default class ShopView { // View layer, used for element rendering, display data, based on (model) data creation constructor() { new EventGroup() // Register all custom events for data transfer AJAX.AjaxTool(Api.GET, Api.ServerApi.getShopList, { // Request the server shopping cart list token: 'hello'// Send the token obtained from the backend for authentication. The token is not obtained here and is replaced with a character}}})Copy the code
-
CreateList (list view)
import Api from '.. /config/Api.js' import Utils from '.. /utils/Utils.js' import ShopEvent from '.. /event/ShopEvent.js' import ShopController from '.. /controller/ShopController.js' export default class CreateList { // View layer, used for element rendering, display data, based on (model) data creation constructor(parentEle) { this.parentEle = parentEle this._shopList = null } set shopList(value) { // Use the object proxy to render the list of items whenever the data changes if (this._shopList) { this.createListEle(this._shopList, this.parentEle) return; } this._shopList = value this.createListEle(value, this.parentEle) } get shopList() { return this._shopList } createListEle(data, parentEle) { let li = Utils.createEle('li', {}, { 'className': 'liItem' }) let img = Utils.createEle('img', {}, { 'src': Api.IMGPATH + data.icon }) let title = Utils.createEle('div', {}, { 'textContent': data.name }) let price = Utils.createEle('span', {}, { 'textContent': data.price + "Yuan" }) li.appendChild(img); li.appendChild(title); li.appendChild(price); li.addEventListener('click'.this.addItemEvent) parentEle.appendChild(li); } addItemEvent = e= > { // When the user clicks add item, the data is sent through the Controller layer to the event bus, which drives the Model layer and modifies the data, and then the Model provides the data refresh table ShopController.dispatch(ShopEvent.ADD_SHOPIING_ITEM, this.shopList) } } Copy the code
conclusion
In general, MVC architecture is a design concept often used by many languages in large projects. It improves code reuse and reduces coupling, making it shine in large projects. In fact, it is not difficult to find that things in life and MVC have similar things in common