Skip to content

Instantly share code, notes, and snippets.

@Ivannnnn
Last active December 12, 2021 12:12
Show Gist options
  • Save Ivannnnn/e14f20141b913700a46676b8ef7f730e to your computer and use it in GitHub Desktop.
Save Ivannnnn/e14f20141b913700a46676b8ef7f730e to your computer and use it in GitHub Desktop.
render html with events
<div id="app"></div>
<script>
const $ = (...args) => {
if (args.length > 1) args.reverse()
const [query, parent = document] = args
return Array.from(parent.querySelectorAll(query))
}
$.create = (html) => {
const div = document.createElement('div')
div.innerHTML = html
return div.children[0]
}
const unique = (arr) => [...new Set(arr)]
const uniqueId = (() => {
let id = 1
return () => id++
})()
const normalizeEventName = (name) =>
name.trim().toLowerCase().replace(/^on/, '')
const mount = (root, elem) => {
root.innerHTML = ''
root.appendChild(elem)
}
const REGEXES = {
openingHtmlTags: /<[^\/].*?>/gm,
nameAndFunc: /\s(on[A-Z].+?\})/gm,
}
/*
*
*
*/
function renderWithEvents(htmlStr, events) {
const eventStore = {}
const newHtmlStr = htmlStr.replace(REGEXES.openingHtmlTags, (tag) => {
const tagId = uniqueId()
return tag.replace(REGEXES.nameAndFunc, (nameAndFunc) => {
const [eventNameCamel, funcName] = nameAndFunc
.replace(/[\{\}]/g, '')
.split('=')
eventStore[tagId + '-' + normalizeEventName(eventNameCamel)] = funcName
return ' data-id="' + tagId + '"'
})
})
const root = $.create(newHtmlStr)
const allEventNames = unique(
Object.keys(eventStore).map((v) => v.split('-')[1])
)
allEventNames.forEach((eventName) => {
root.addEventListener(eventName, (e) => {
const funcName =
eventStore[e.target.getAttribute('data-id') + '-' + eventName]
funcName && events[funcName] && events[funcName](e)
})
})
return $(root, '[id]').reduce(
(acc, el) => {
acc['$' + el.id] = el
return acc
},
{ $root: root }
)
}
/*
*
*
*
*/
function runInputExample() {
const defaultVal = 'Ivan'
const template = `<div>
<input id='input' type='text' onInput={input} value="${defaultVal}"/>
<h3 id='header'>${defaultVal}</h3>
<button onClick={rerender}>re-render</button>
</div>`
function render() {
const events = {
input: (e) => {
$header.innerText = e.target.value
},
rerender: () => {
render()
},
}
const { $root, $input, $header } = renderWithEvents(template, events)
mount($('#app')[0], $root)
}
render()
}
runInputExample()
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment