What is MVC?
- M is model, namely data model, responsible for data-related tasks, including adding, deleting, modifying and checking data
- V is the view, the view layer, the interface that the user can see
- C is the Controller, the Controller that listens for user events and then calls M and V to update data and views
Next, pseudo-code will be used to represent the work content of the three parts
1.1 Model Data Model
/ / sample
let Model={
data:{data source},create:{add data},delete:{delete data},update(data){
Object.assign(m.data,data)// Replace old data with new data
eventBus.trigger('m:update')//eventBus triggers the 'M :update' message, notifying the View to refresh the interface
},
get:{get data}}Copy the code
1.2 View View layer
/ / sample
let View={
el: The element to refresh, HTML:'Refresh content to display on the page'
init(){v.l: Initialize the element to be refreshed},render(){refresh page}}Copy the code
1.3 Controller Controller
By binding events, the controller calls M and V to update data and views based on user actions
let Controller={
init(){
v.init()// Initialize the View
v.render()// Render the page for the first time
c.autoBindEvents()// Automatic event binding
eventBus.on('m:update'.() = >{v.render()}// When enentsBus triggers 'm:update', the View is refreshed},events:{events are stored as hash table records},/ / such as:
events: {
'click #add1': 'add'.'click #minus1': 'minus'.'click #mul2': 'mul'.'click #divide2': 'div',},add() {
m.update({n: m.data.n + 1})},minus() {
m.update({n: m.data.n - 1})},mul() {
m.update({n: m.data.n * 2})},div() {
m.update({n: m.data.n / 2})},method(){data= new data m.pdate (data)// Controller notifies model to update data
},
autoBindEvents(){
for (let key in c.events) { // Iterate through the Events table and automatically bind events
const value = c[c.events[key]]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex) / / get a 'click'
const part2 = key.slice(spaceIndex + 1) / / get '# add1'
v.el.on(part1, part2, value)
}
}
Copy the code
1.4 the MVC instance
Our goal is to make an addition, subtraction, multiplication and division calculator
The value changes every time the add, subtract, multiply, and divide buttons are clicked. The basic idea is to listen for the click event
Then the MVC action would look like this
import './app1.css'
import $ from 'jquery'
const eventBus = $(window)
// All data related to m
const m = {
data: {
n: parseInt(localStorage.getItem('n'))},create() {},
delete() {},
update(data) {
Object.assign(m.data, data)
eventBus.trigger('m:updated')
localStorage.setItem('n', m.data.n)
},
get(){}}// All views are placed in v
const v = {
el: null.html: `
{{n}}
< button id = "minus1" > 1 < / button > < button id = "mul2" > * 2 < / button > < button id = "divide2" > present 2 < / button > < / div > < / div > `
.init(container) {
v.el = $(container)
},
render(n) {
if(v.el.children.length ! = =0) v.el.empty()
$(v.html.replace('{{n}}', n))
.appendTo(v.el)
}
}
// all others are c
const c = {
init(container) {
v.init(container)
v.render(m.data.n) // view = render(data)
c.autoBindEvents()
eventBus.on('m:updated'.() = > {
console.log('here')
v.render(m.data.n)
})
},
events: {
'click #add1': 'add'.'click #minus1': 'minus'.'click #mul2': 'mul'.'click #divide2': 'div',},add() {
m.update({n: m.data.n + 1})},minus() {
m.update({n: m.data.n - 1})},mul() {
m.update({n: m.data.n * 2})},div() {
m.update({n: m.data.n / 2})},autoBindEvents() {
for (let key in c.events) {
const value = c[c.events[key]]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex)
const part2 = key.slice(spaceIndex + 1)
v.el.on(part1, part2, value)
}
}
}
export default c
Copy the code
In the external reference is direct
Import x from './app1.js' x.i. Nit ('#app1') pass in the container div and write an HTML <div id="app1"></div> as the containerCopy the code
Second, the EventBus
2.1 What is EventBus?
EventBus is primarily used for communication between objects, such as in the example above, where the Model data Model and the View Model are unaware of each other’s existence but need to communicate
Conclusion: Using eventBus can meet the minimum knowledge principle, m and V do not know each other’s details, but can call each other’s functions
2.2 What apis does EventBus have?
EventBus provides apis such as ON, off, and Trigger. On is used to listen for events and trigger is used to trigger events
For example, in the MVC model above, when the M data model is updated, the trigger triggers an event
const m = {
....
update(data) {
Object.assign(m.data, data)
eventBus.trigger('m:updated') // Inform the View layer that I have updated the data and the view should start working
localStorage.setItem('n', m.data.n)
},
....
}
Copy the code
Then in controller, the Controller listens for events with ON and tells the View model to re-render the page
const c = {
init(container) {
v.init(container)
v.render(m.data.n) // view = render(data)
c.autoBindEvents()
eventBus.on('m:updated'.() = > { // Controller will use on to listen for events,
// Then inform the View model to re-render the page
console.log('here')
v.render(m.data.n)
})
},
...
}
Copy the code
Table driver programming
When we need to judge more than three cases and make corresponding things, we often need to write a lot of If and else, which is not very readable. In order to improve the readability of the code, we can use table-driven programming, save the value used to judge the If condition into a hash table, and then value it from the table
For example:
In the example above, I need to determine which button is clicked and then modify the value of output.
Traditionally, we would bind the click events to each of the four buttons and then write the four callbacks to change the values
$button1.on('click'.() = > {
let n = parseInt($number.text())
n += 1
localStorage.setItem('n', n)
$number.text(n)
})
$button2.on('click'.() = > {
let n = parseInt($number.text())
n -= 1
localStorage.setItem('n', n)
$number.text(n)
})
$button3.on('click'.() = > {
let n = parseInt($number.text())
n = n * 2
localStorage.setItem('n', n)
$number.text(n)
})
$button4.on('click'.() = > {
let n = parseInt($number.text())
n = n/2
localStorage.setItem('n', n) $number.text(n)}) -------- after the event delegate -------const c = {
init(container) {
v.init(container)
v.render(m.data.n)
c.BindEvents()
}
BindEvents() {
v.el.on('click'.'#add1'.() = > {
m.data.n += 1
v.render(m.data.n)
})
v.el.on('click'.'#minus1'.() = > {
m.data.n -= 1
v.render(m.data.n)
})
v.el.on('click'.'#mul2'.() = > {
m.data.n *= 2
v.render(m.data.n)
})
v.el.on('click'.'#divide2'.() = > {
m.data.n /= 2
v.render(m.data.n)
})
}
}
Copy the code
But this is too much trouble, update the measures:
- Bind the parent element of the add, subtract, multiply and divide buttons with only one event listener
- Use hash tables to store buttons and their corresponding operations
const c = {
events: {
'click #add1': 'add'.'click #minus1': 'minus'.'click #mul2': 'mul'.'click #divide2': 'div',},add() {
m.update({n: m.data.n + 1})},minus() {
m.update({n: m.data.n - 1})},mul() {
m.update({n: m.data.n * 2})},div() {
m.update({n: m.data.n / 2})},autoBindEvents() {
for (let key in c.events) {
const value = c[c.events[key]]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex)
const part2 = key.slice(spaceIndex + 1)
v.el.on(part1, part2, value)
}
}
Copy the code
Four, modular
- Modularity is the extraction of relatively independent code from a large piece of code into small and concise modules
- Each module is independent of each other, which facilitates future maintenance and modification
- ES6 syntax introduces Import and export to achieve modularity
When we package the Controller model in app1.js, we export the Controller:
export default c // Export by default
export {c} // Another way to export. Remember to put curly braces
Copy the code
In main.js we want to use controller:
import x from './app1.js'Is equivalent toimport {default as x} from './app1.js'
x.init('#app1')
Copy the code
More examples of rename exports:
// inside module.mjs
export { function1, function2 };
// inside main.mjs
import { function1 as newFunctionName,
function2 as anotherNewFunctionName } from '/modules/module.mjs';
Copy the code
References:
Developer.mozilla.org/zh-CN/docs/…
This article is originally published by FJL. The copyright of this article belongs to me and Hungry People Valley