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 provideson,offtriggerSuch as API,onUsed to listen for events,triggerUsed to trigger events,offUsed 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

  1. Developer.mozilla.org/zh-CN/docs/…
  2. zhuanlan.zhihu.com/p/96985491