如何创建一个JavaScript HTML生成器

I recently built a text editor web app in vanilla Javascript, and after coding for a few hours, I quickly became tired of constantly creating DOM elements. I was creating the elements on the fly because they required dynamic IDs, Event listeners and content every time they were rendered. I quickly realized that a template system would be better for my needs and clean up my classes.

我最近用香草Javascript构建了一个文本编辑器Web应用程序,在编码了几个小时之后,我很快就厌倦了不断创建DOM元素。 我正在动态创建元素,因为它们每次渲染时都需要动态ID,事件侦听器和内容。 我很快意识到模板系统会更好地满足我的需求并清理班级。

I decided to build my own templating engine which I decided to call DOMinator just for fun. I will walk through the basic steps I took and the code that I used to create this.

我决定构建自己的模板引擎,出于娱乐性考虑,我决定将其称为DOMinator。 我将逐步介绍我所采取的基本步骤以及用于创建此代码的代码。

First I wanted to create a simple format for templates so I created a new file called templates.js in which I have a single object Templates filled with each of the templates I use. I built the templates as functions so I can pass variables to them. this is a template for my Doc Icons.

首先,我想为模板创建一种简单的格式,所以我创建了一个名为templates.js的新文件,在其中我有一个对象Templates填充了我使用的每个模板。 我将模板构建为函数,以便可以将变量传递给它们。 这是我的文档图标的模板。

const Templates = {
docIcon: function(obj) {
return {
tag: 'div',
id: obj.id,
classes: ['doc-icon'],
properties: {
title: obj.name,
tabIndex: 0
},
children: [
{
tag: 'div',
classes: ['doc-icon-header'],
children: [
{ tag: 'h3', content: obj.name }
]
},
{
tag: 'p',
content: obj.exerp
},
{
tag: 'div',
id: 'docControls',
classes: ['doc-controls'],
children: [
{
tag: 'button',
classes: ['doc-control'],
id: 'moveDoc',
children: [
{
tag: 'i',
classes: ['fa', 'fa-folder']
}
]
},
{
tag: 'button',
classes: ['doc-control'],
id: 'deleteDoc',
children: [
{
tag: 'i',
classes: ['fa', 'fa-trash']
}
]
}
]
}
]
}
}

As you can see, the tag, id, and classes are explicitly defined as keys for our objects, but anything else is passed in the properties key. We also have an array of children, with each child having the same format as the parent. In theory we could infinitely nest DOM elements with this format.

如您所见,标记,标识和类被明确定义为对象的键,但是其他任何内容都通过属性键传递。 我们也有一系列子代,每个子代与父代的格式相同。 从理论上讲,我们可以使用这种格式无限嵌套DOM元素。

Once we have this simple Javascript Object format for our templates, it’s easy to build a ton of them pretty quickly, but how do we convert to HTML and add to the DOM?

一旦我们的模板有了这种简单的Javascript对象格式,就可以很容易地快速构建大量的模板,但是我们如何转换为HTML并添加到DOM中呢?

I created a class called Dominator with instances representing a DOM element as an object. An instance would look very much like our template, except the dynamic values would be applied. I just use Object.assign() to essentially replicate the template.

我创建了一个名为Dominator的类,其实例将DOM元素表示为一个对象。 实例看起来非常类似于我们的模板,只是将应用动态值。 我只是使用Object.assign()从本质上复制模板。

class Dominator {
constructor(object) {
Object.assign(this, object)
}
}

Next we need to figure out how to create the children. We can use a for loop to recursively create new instances of the class for the children. We then push the children into an empty initialized array, and after looping through we assign this.children to equal our array.

接下来,我们需要弄清楚如何创建子代。 我们可以使用for循环为子代递归创建类的新实例。 然后,我们将子级推入一个空的初始化数组,并在循环之后将this.children分配为等于我们的数组。

----
constructor(object) {
Object.assign(this, object)
let childObjects = []
if (object.children){
for (const child of object.children) {
let childObject = new Dominator(child)
childObjects.push(childObject)
}
}
this.children = childObjects
this.element = this.domElement
}
----

So far we have an object that is a copy of the template with our content applied to it. Not useful yet. Next up we need to turn these into DOM elements. I created a get function called domElement() to return a generated DOM element. I used get so we can update our properties and regenerate the element whenever we want.

到目前为止,我们有一个对象,它是模板的副本,其内容已应用到模板。 还没有用。 接下来,我们需要将它们变成DOM元素。 我创建了一个称为domElement()的get函数,以返回生成的DOM元素。 我使用了get,以便我们可以随时更新属性并重新生成元素。

The first part of the function creates the element and sets the basic properties.

函数的第一部分创建元素并设置基本属性。

get domElement() {
const domElement = document.createElement(this.tag)
if (this.id) domElement.id = this.id
if (this.content) domElement.innerText = this.content
----- return domElement
}

The next three things that need to happen are iterate and assign properties, iterate and set classes, and iterate and append children to our domElement.

接下来需要进行的三件事是:迭代和分配属性,迭代和设置类,以及将子代迭代并追加到domElement中。

get domElement() {
const domElement = document.createElement(this.tag)
if (this.id) domElement.id = this.id
if (this.content) domElement.innerText = this.content if (this.properties) for (const prop in this.properties) {
domElement[prop] = this.properties[prop]
}
if (this.classes) for (const cssClass of this.classes) {
domElement.classList.add(cssClass)
}
if (this.children) for (const child of this.children) {
domElement.append(child.domElement)
if (child.id) this[child.id] = child.domElement
}
this.element = domElement return domElement
}

As you can see, we are conditionally checking everything to be sure it exists in our template and then applying those things to our domElement and then returning it.

如您所见,我们将有条件地检查所有内容以确保其存在于模板中,然后将这些内容应用于domElement并返回它。

Our full class looks like this so far:

到目前为止,我们的全班看起来像这样:

class Dominator {
constructor(object) {
Object.assign(this, object)
let childObjects = []
if (object.children){
for (const child of object.children) {
let childObject = new Dominator(child)
childObjects.push(childObject)
}
}
this.children = childObjects
this.element = this.domElement
}
get domElement() {
const domElement = document.createElement(this.tag)
if (this.id) domElement.id = this.id
if (this.content) domElement.innerText = this.content
if (this.properties) for (const prop in this.properties) {
domElement[prop] = this.properties[prop]
}
if (this.classes) for (const cssClass of this.classes) {
domElement.classList.add(cssClass)
}
if (this.children) for (const child of this.children) {
domElement.append(child.domElement)
if (child.id) this[child.id] = child.domElement
}
this.element = domElement
return domElement
}
}

Let’s see it in action!

让我们看看它的作用!

get docIcon() {
const dominator = new Dominator(Templates.docIcon(this))
const div = dominator.domElement
div.addEventListener('click', this.openDoc.bind(this))
div.querySelector('#deleteDoc').addEventListener('click', this.deleteDoc.bind(this))
div.querySelector('#moveDoc').addEventListener('click', this.moveDoc.bind(this))
this.icon = div
return div
}

How can we simplify the event listener process? Let’s add a new function called findChildById().

我们如何简化事件监听器过程? 让我们添加一个名为findChildById()的新函数。

findChildById(id) {
if (this.children) {
for (const child of this.children) {
if (child.id === id) {
return child
} else if (child.children) {
let found = child.findChildById(id)
if (found) return found
}
}
}
return false
}

Using a little recursion we can find the child instance of Dominator to make changes to it. Now we can create an array called this.eventListeners = [] in our constructor which we will add our event listeners to be assigned to the DOM element later on.

使用一点递归,我们可以找到Dominator的子实例来对其进行更改。 现在,我们可以在构造函数中创建一个名为this.eventListeners = []的数组, this.eventListeners = []将添加事件监听器以分配给DOM元素。

To add events I wanted it to be as simple as possible, so the callback is first, then the optional ID and finally the event type which defaults to click for my convenience. The ID argument assumes we are looking for a child with that ID.

为了添加事件,我希望它尽可能简单,所以首先是回调,然后是可选ID,最后是事件类型,为方便起见,默认单击该事件类型。 ID参数假设我们正在寻找具有该ID的孩子。

event(action, id, type = 'click') {
if (id) {
const node = this.findChildById(id)
if (node) {
node.eventListeners.push({type: type, action: action})
}
} else {
this.eventListeners.push({type: type, action: action})
}
}

Finally in our get domElement() function, we need the following:

最后,在我们的get domElement()函数中,我们需要以下内容:

if (this.eventListeners) for (const eventListener of this.eventListeners) {
domElement.addEventListener(eventListener.type, eventListener.action)
}

Now we can refactor our code from earlier:

现在,我们可以从早期重构代码:

get docIcon() {
const dominator = new Dominator(Templates.docIcon(this))
dominator.event(this.openDoc.bind(this))
dominator.event(this.deleteDoc.bind(this), 'deleteDoc')
dominator.event(this.moveDoc.bind(this), 'moveDoc')
const div = dominator.domElement
this.icon = div
return div
}

Viola! Much cleaner.

中提琴! 清洁得多。

Here is the entire code for our Dominator:

这是我们统治者的全部代码:

class Dominator {
constructor(object) {
Object.assign(this, object)
let childObjects = []
if (object.children){
for (const child of object.children) {
let childObject = new Dominator(child)
childObjects.push(childObject)
}
}
this.eventListeners = []
this.children = childObjects
this.element = this.domElement
}
get domElement() {
const domElement = document.createElement(this.tag)
if (this.id) domElement.id = this.id
if (this.content) domElement.innerText = this.content
if (this.properties) for (const prop in this.properties) {
domElement[prop] = this.properties[prop]
}
if (this.classes) for (const cssClass of this.classes) {
domElement.classList.add(cssClass)
}
if (this.children) for (const child of this.children) {
domElement.append(child.domElement)
if (child.id) this[child.id] = child.domElement
}
if (this.eventListeners) for (const eventListener of this.eventListeners) {
domElement.addEventListener(eventListener.type, eventListener.action)
}
this.element = domElement
return domElement
}
findChildById(id) {
if (this.children) {
for (const child of this.children) {
if (child.id === id) {
return child
} else if (child.children) {
let found = child.findChildById(id)
if (found) return found
}
}
}
return false
}
event(action, id, type = 'click') {
if (id) {
const node = this.findChildById(id)
if (node) {
node.eventListeners.push({type: type, action: action})
}
} else {
this.eventListeners.push({type: type, action: action})
}
}
}

翻译自: https://medium.com/@altmod/how-to-create-a-javascript-html-generator-439f52b88ccc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值