A series of algorithms are encapsulated and made interchangeable with each other. The encapsulated algorithm is independent and cannot be changed externally

The data dictionary

In my understanding, data dictionaries naturally fit the concept of strategic patterns and are therefore classified as applications of strategic patterns

const dates = ['day'.'一'.'二'.'三'.'four'.'five'.'六']
console.log('Today is Sunday${dates[new Date().getDay()]}`)

const statusArr = ['save'.'edit'.'review'.'Approved'.'Audit failed'.'off']
statusArr[0] / / = > save
statusArr[3] //=> The audit passed
statusArr[6] / / = > shut down
// This is a simple example of enumeration state echo
const statusObj = {
    'new':'new'.'edit':'edit'.'pass':'review'.'close':'off'
}
let code = 'close'
statusObj[code]
// Output in non-enumeration state The actual service may have non-enumeration types that can still be displayed in this way

// The following is a data dictionary simulating the I18N scenario
const DEFAULT = 'zh-CN' // Read by default
const dictionary = { // Internationalize the dictionary table
  'zh-CN': {hello:'hello'.message:'message'.home:'home'
  },
  'en': {hello:'hello'.message:'message'.home:'home'}}// Install the new data dictionary method
function installNew(params,info){
  Object.entries(info).forEach(([key,text]) = >{
      // Convert the passed object to an array of key-value pairs
      // params is the field to be followed
      // The key here corresponds to the language
      // Text corresponds to actual text
      dictionary[key][params] = text
  })
}

// Translation methods
function i18n(language,params){
  const info = dictionary[language] || dictionary[DEFAULT]
    // Fetch the corresponding language object of the dictionary according to the incoming language
  return info[params] // Returns the corresponding argument of the language object
}


installNew('user', {// The user field needs to be installed
    'zh-CN':'users'.en:'user'
})

i18n('zh-CN'.'user') / / = > user
i18n('en'.'user') // => user

i18n('zh-CN'.'home') / / = > home page
i18n('en'.'home') // => home
i18n('jp'.'home') / / = > home page

Copy the code

Automatic distribution

🌰 bus terminal will have different lines of buses between them the form of the line may be partially overlapped, the destination station may not be the same, so we choose a route from the bus must be in accordance with the existing route driving strategy mode of the behavior is similar to Qi

// Here we assume a business scenario and implement it using the policy pattern
// 1. Press a to output the description 'Hello'
// 2. Press b to pop up a timestamp
// 3. Press S to perform the a key logic and then perform the B key logic without increasing the policy execution times
// 4. Press ESC to output the number of times for executing different policies. The number of times for executing different policies is automatically added
const bus = {
    run(e){ // The automatic distribution intersection is used as the bus terminal in the example
        const {key} = e // Retrieves the key from the incoming keyboard event
        const fn = this.methods[key] // From its own method
        if(fn){
            this.nums[key] ? this.nums[key]++ : this.nums[key] = 1 // Check if the policy has been executed. If not, set it to 1. If so, increment it by 1
            fn.call(this,e) // Change the method's this pointer so that it can read the entire policy object}},nums: {},// => Save execution count data
    methods: {a(){
            console.log('hello')},b(){
            alert(+new Date()},s(){
            this.methods.a()
            this.methods.b()
        },
        Escape(){
            console.table(this.nums)
        }
    }
}
window.addEventListener('keydown'.e= >bus.run(e))
Copy the code

Use policy pattern to develop a table class for one-way data updates and arrow key movement

  1. Support shortcut keys up, down and left to move the focus
  2. Table data can be added/deleted/edited and synchronized to the data source in real time
<! DOCTYPEhtml>
<html>

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title></title>
    <style>
        table {
            border-collapse: collapse;

        }

        th.td {
            border: 1px solid #9c9c9c;
            width: 200px;
        }

        input[type="text"] {
            padding: 0px;
            margin: 0px;
            outline: 1px;
            width: 100%;
            border: 0px;
            height: 30px;
        }

        input[type="text"]:focus {
            box-shadow: 0px 0px 1px 2px #9f9f9f;

        }
    </style>
</head>

<body>
<input value="Add a row" type="button" e-click="addRow" />
<table>
    <tbody></tbody>
</table>
</body>
<script>
    function on(type, lister) { // Global listener encapsulation simplifies the amount of code
        return window.addEventListener(type, lister)
    }
    function require(msg) {// Mandatory parameter verification
        throw new Error(msg)
    }

    class MyTable {
        _config = { // Default configuration
            el: 'table'.cols: [].data: []
        }
        dom = null // An instance of the operation
        constructor(config) {
            Object.assign(this._config, config)// Copy the incoming configuration to itself
            const { el } = this._config // Extract parameters
            this.dom = document.querySelector(el) || require('Dom doesn't exist') // Don't get dom instantiation
            this.renderHeader() // Render the header
            this.load() // Render the content
            this.addLiser() // monitor table
        }
        addLiser() {
            on('click'.e= > {
            // The element is clicked => extract the source dom => try to extract the e-click attribute configured on the DOM =
                // Listen on the click event source dom if there is an e-click attribute automatically read its corresponding method name to execute
                const { target } = e
                const eName = target.attributes['e-click']
                if (eName) {
                    this[eName.value](e)
                }
            })
            on('input'.e= > {
            // Element start input event => Try to extract the value of e-input => If the instance itself has a corresponding method => actively call method pass event => Extract event source input box custom index field => Extract the data object corresponding to the current row according to index and dynamically set the value of the corresponding property through field
                // Listen on the click event source dom if there is an e-input attribute automatically read its own corresponding method name to execute
                const { target } = e
                const eName = target.attributes['e-input']
                if (eName) {
                    this[eName.value](e)
                }
            })
            on('keydown'.e= > {
                // Listen for directional keys automatically distributed to the corresponding switch focus method inside the instance
                const { key, target } = e
                if (target.attributes.focus && typeof this[key] === 'function') {
                    const { index, field } = target.dataset
                    this[key](target, index * 1, field)
                }
            })
        }
        getNext(index, field) {
            // Get the focus content of the incoming index row and field
            return this.dom.querySelector(`[data-index="${index}"][data-field="${field}"][focus]`)}getFocusList(index) {
            // Get all focusable DOM for the current row
            return this.dom.querySelectorAll(`[data-index="${index}"][focus]`)}ArrowUp(target, index, field) {
            // Get the input box of the same field on the previous line without using itself
            const el = this.getNext(index - 1, field) || target
            el.focus()
            el.select()
        }
        ArrowDown(target, index, field) {
            const el = this.getNext(index + 1, field) || target
            el.focus()
            el.select()
        }
        ArrowLeft(target, index, field) {
            // Get all focusable input fields for the current row and find the last one based on its own index
            const els = [...this.dom.querySelectorAll(`[data-index="${index}"][focus]`)]
            const i = els.indexOf(target)
            const prv = els[i - 1] || target
            prv.focus()
            prv.select()

        }
        ArrowRight(target, index, field) {
            const els = [...this.dom.querySelectorAll(`[data-index="${index}"][focus]`)]
            const i = els.indexOf(target)
            const next = els[i + 1] || target
            next.focus()
            next.select()

        }

        renderHeader() {
            const vm = document.createElement('table')
            const ths = this._config.cols.reduce((prv, next) = > `${prv}<th>${next.title || ' '}</th>`.' ')
            vm.innerHTML = `<thead><tr>${ths}< th > action < / th > < / tr > < thead > `
            this.dom.append(... vm.children) }load() {
            const { cols, data } = this._config
            const body = this.dom.querySelector('tbody')
            // Render a string of all line contents
            const trs = data.reduce((prv, next, index) = > {
                return prv + MyTable.renderTr(cols, next, index)
            }, ' ')
            body.innerHTML = trs // Replace the table body
            console.table(this._config.data)
        }

        static renderTr(cols, row, index) {
            // Render row data in batches
            return `<tr>
                ${cols.reduce((prv, next) => {
                return prv + MyTable.renderTD(row, index, next.field)
            }, ' ')}<td> <input value=" delete "type="button" e-click="removeRow" data-index="${index}"/>
                </td>
            </tr>`

        }
        static renderTD(row, index, field) {
            // Render single data content with TD tags containing input
            // focus tag => Can focus content
            // e-input => The input event is triggered after the input
            // data-index => Index of the data object
            // data-field => Data field
            return `<td><input focus type="text" e-input="update" data-index="${index}" data-field="${field}" value="${row[field] || ' '}" /></td>`
        }




        addRow() {
            // Push empty data
            this._config.data.push({})
            // Redraw the table
            this.load()
        }
        removeRow(e) {
            const { target } = e
            const { index } = target.dataset
            // Retrieve the index
            this._config.data.splice(index, 1)
            // Delete the index contents of the array
            this.load()
            // Redraw the table
        }
        update(e) {
            const { target } = e
            const { index, field, value } = target.dataset
            // Extract index and data fields
            // Retrieve objects by index update values by field
            this._config.data[index][field] = target.value
            console.table(this._config.data)
        }
    }
    new MyTable({
        cols: [{field: 'msg'.title: 'message'
            },
            {
                field: 'user'.title: 'users'}, {field: 'remark'.title: 'note'}].data: [{}]
    })
</script>

</html>
Copy the code