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:

  1. Bind the parent element of the add, subtract, multiply and divide buttons with only one event listener
  2. 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