Skip to content

Instantly share code, notes, and snippets.

@dmitryshelomanov
Created July 6, 2018 11:30
Show Gist options
  • Save dmitryshelomanov/01e76697122923b28ea785bdfe1c4dab to your computer and use it in GitHub Desktop.
Save dmitryshelomanov/01e76697122923b28ea785bdfe1c4dab to your computer and use it in GitHub Desktop.
class JsEngine {
constructor(options) {
this.options = options
this.models = this.options.data || {}
this.lifecycle = this.options.lifecycle || {}
this.bindings = {}
this.elementToUpdate = {}
this.root = document.querySelector(this.options.el)
this.searchBindModel()
this.proxyBind()
}
searchBindModel() {
this.lifecycle.componentWillMount
&& this.lifecycle.componentWillMount.call({ data: this.models })
this.root.querySelectorAll('[bind]')
.forEach((element) => {
this.bindings[element.getAttribute('bind')] = element
})
}
proxyBind() {
const self = this
this.models = new Proxy(this.models, {
set (target, prop, value) {
const element = self.bindings[prop]
self.updateTextBind(prop, value)
element.value = value
element.setAttribute('value', value)
return Reflect.set(target, prop, value)
}
})
this.setInitialModel()
this.inputBindingReaction()
this.lifecycle.componentDidMount
&& this.lifecycle.componentDidMount.call({ data: this.models })
this.setTextModels()
}
setInitialModel() {
Object.keys(this.bindings)
.map((modelName) => {
const element = this.bindings[modelName]
const value = this.models[modelName]
element.value = value
element.setAttribute('value', value)
})
}
inputBindingReaction() {
Object.keys(this.bindings)
.map((modelName) => {
const element = this.bindings[modelName]
element
.addEventListener('input', (event) => {
this.models[modelName] = event.target.value
})
})
}
setTextModels() {
let { children } = this.root
for (let i = 0; i < children.length; i++) {
let replaced = children[i].innerText.replace(/{{2}(.+)}{2}/igm, (_, matching) => {
matching = matching.trim()
this.elementToUpdate[matching] = children[i]
if (this.models[matching]) {
return this.models[matching]
}
return undefined
})
if (replaced) {
children[i].innerText = replaced
}
}
}
updateTextBind(prop, currentValue = null) {
const element = this.elementToUpdate[prop] || {}
element.innerText = currentValue
}
}
@dmitryshelomanov
Copy link
Author

example
// index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>js-engine</title>
</head>
<body>
  <div id="app">
    <input type="text" bind="name" />
    <input type="text" bind="lastName" />
    <p>{{ name }}</p>
    <p>{{ lastName }}</p>
  </div>
  <script src="js-engine.js"></script>
  <script src="app.js"></script>
</body>
</html>

// app.js

const engine = new JsEngine({
  el: '#app',
  data: {
    name: 'dima112',
    lastName: 'shelomanov',
  },
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment