Design patterns are names for common code.
- Why design patterns? DRY Don’t Repeat Yourself
Because of code-level duplication, page-level duplication, you should come up with a one-size-fits-all approach to optimizing your code structure. MVC is a panacea
“One” MVC three objects
- Divide the page into modules, and each module can be written as three objects, named M, V, and C
- M — Model, data Model, responsible for data-related tasks, operation of all data (add, delete, modify and check)
- V — View, the View, is responsible for all the UI, the interface that the user can see
- C — Controller, the Controller that listens for user events and then calls M and V to update data and views
1. Data Model
Model Data management, including data logic, data requests, data storage and other functions. The front-end Model is mainly responsible for AJAX requests or LocalStorage.
Pseudocode sample
const model = {
data: {initialize data},create(){add data},delete(){delete data},update(data){update data},get(){read data}}Copy the code
2. View
The View is responsible for the user interface, and the front View is responsible for HTML rendering.
Pseudocode sample
const view={
// The element to refresh
el: null.// What is displayed on the page
html: `<div class="html"></div>`.// Initialize HTML
init(container){
v.el = $(container)
},
// Refresh the page
render(){Render data to page}}Copy the code
3. Controller
The Controller handles the View events and updates the Model; It also listens for changes to the Model and updates the View, and the Controller controls everything else.
Pseudocode sample
const controller = {
init(){
v.init() // View initialization
v.render() // View = render(data)
c.autoBindEvents() // Automatically bind events
eventBus.on('m:update'.() = > { v.render() }) // View refreshes when eventBus triggers 'm:update'
},
events:{events are hashed},method(){data = new data after change m.update(data)},autoBindEvents(){automatic binding event}}Copy the code
4. MVC example
An addition, subtraction, multiplication and division calculator that changes the value every time the corresponding button is clicked. The basic idea is to listen for click events.
Its MVC operations are as follows:
The code shown
import './app1.css'
import $ from 'jquery'
const eventBus = $(window)
// All data related to M
const m = {
data: {
// initialize the number n from the local database
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}}
.// Initialize HTML
init(container){
v.el = $(container)
},
// Render data to the page
render(n){
if(v.el.children.length === null) {// If not rendered
} else {
v.el.empty()
}
$(v.html.replace('{{n}}', n)).appendTo(v.el)
},
}
// all others are C
const c = {
init(container){
v.init(container) // Render HTML for the first time
v.render(m.data.n) // First view = render(data)
c.autoBindEvents() // Bind events
eventBus.on('m:updated'.() = >{
v.render(m.data.n)
})
},
events: {
'click #add1': 'add'.'click #minus1': 'minus'.'click #mul2': 'mul'.'click #divide2': 'div'
},
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)
}
},
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}}})export default c
Copy the code
“The second” EventBus
- EventBus 就是 EventTarget
- EventBus is also a design pattern or framework for optimizing and simplifying communication between components/objects.
- For example, in the example above, the Model data Model and the View Model are unaware of each other’s existence but need to communicate, so EventBus is used
- Advantages Using eventBus can meet the principle of minimum knowledge. M and V do not know each other’s details, but they can call each other’s functions. Simple code; Fast and lightweight.
EventBus API
- EventBus provides
on
,off
和trigger
Such as API,on
Used to listen for events,trigger
Used to trigger events,off
Used to cancel listening
The code examples
- Declare your own EventBus in a JS file to simulate using EventBus functionality. For convenience, this is done by introducing jquery.
import $ from 'jquery'
const eventBus = $(window)
Copy the code
- Using on method in one place and trigger method in another place, the data communication function is preliminarily realized.
- In the MVC Model above, the Trigger triggers an event when the Model data Model is updated
- The Controller then uses on to listen for events that tell the View model to re-render the page
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
const c = {
init(container) {
v.init(container)
v.render(m.data.n) // view = render(data)
c.autoBindEvents()
eventBus.on('m:updated'.() = > { // Use on to listen for events to tell the view model to re-render the page
console.log('here')
v.render(m.data.n)
})
},
...
}
Copy the code
“Three” table driver programming
- Table Driven Approach (Table Driven Approach) simply refers to the method of looking up tables to obtain values.
- Table driven is a programming mode in which tables can store data, instructions, or functions.
- When the value is small, we can use logical statements (if/else or case DO) to obtain the value. However, as the value increases, the logical statements become longer and longer. In this case, we can use table-driven programming to store the value used to determine the if condition into a hash table, and then value from the table.
- One important use of table-driven programming in JavaScript is automatic event binding.
The code shown
In the MVC example above, I need to determine which button is clicked, then modify the value of output and push it by event. There is jquery event monitoring method in the binding event.
-------- after the event delegate -------const c = {
init(container) {
v.init(container)
v.render(m.data.n)
c.BindEvents() // Bind events
}
BindEvents() {
/ / the jquery object
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 the code above, there’s a lot of overlap. Table driven programming simplifies this code. Hide those that are the same and similar, leaving only those that are needed.
Solution: 1. Bind the parent element of the add, subtract, multiply and divide buttons, and use only one event to listen on 2. Use hash tables to store buttons and their corresponding operations
const c = {
init(){...// This is called an automatic binding event
c.autoBindEvents()
},
// Events use hash tables
events: {
'click #add1': 'add'.'click #minus1': 'minus'.'click #mul2': 'mul'.'click #divide2': 'div'
},
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)
}
},
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}}})Copy the code
“Four” modular
-
A Web page can be divided into different modules according to different functions, and each module has different implementation methods and technologies. The introduction of modularity can cut off the mutual influence of each module, so that the code can be better optimized in a single module.
-
A module is an independent file, and all variables inside the file cannot be obtained externally. If the external wants to read a variable inside the module, IMPORT and export are introduced into the syntax of ES6 to achieve this.
-
Modularization can reduce code coupling, reduce duplicate code, improve code reuse, and make the project structure clearer and easier to maintain.
References
- Developer.mozilla.org/zh-CN/docs/…
- zhuanlan.zhihu.com/p/96985491