前几天,我收到了一位朋友的来信。 他有一些 HTML、CSS 和 JavaScript 代码,但它们的行为并不像他预期的那样。 HTML 中有一些占位符,JavaScript 中有一些数据,他假设这些数据会填充占位符。
对于我们这些有一定 Web 知识的人来说,我们可以看到为什么它没有按他预期的方式工作。 但我认为从他的角度看待问题也很有价值,然后看看解决方案,希望这些解决方案和最初的问题一样简单。
HTML 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
<link rel="stylesheet" href="test.css">
<script src="data.js"></script>
</head>
<body>
<section>
<div>{company_name}</div>
</section>
</body>
</html>
JavaScript 代码如下:
var company_data = {
"{company_name}" : "SOME COMPANY",
};
这段代码没有任何错误。
这段代码完全有效。 它们已正确链接。 它将运行。 它只是什么也不做,除了在屏幕上渲染 {company_name}
。 预期它会渲染 SOME COMPANY 到屏幕上,用来自 JavaScript 文件的数据替换 {company_name}
占位符。
让我们用一行代码来解决它。
在这种情况下,要显示正确的公司名称,我们需要在 DOM 中选择该元素,并用我们的数据替换其内容。 我们可以通过在 JavaScript 中添加这额外的一行代码来实现这一点
var company_data = {
"{company_name}": "SOME COMPANY"
};
document.querySelector("div").innerHTML = company_data["{company_name}"];
这并不特别可重用或具有弹性,但嘿,它也没有过度思考或过度使用工具。
预期是使用模板
我认为我们现在可以看出,他希望发生的事情是,这种模板可以自动发生。 提供一个对象,其键与 HTML 中的键匹配,HTML 中的内容会自动被替换。 但使用原始的 Web 技术无法实现这种效果。
毫不夸张地说,有数百种方法可以处理这种情况。 以下是我的脑海中想到的一些方法。
- 使用模板语言,例如 Handlebars 或 Mustache
- 使用静态站点生成器,例如 Eleventy,它默认使用 Liquid
- 创建 HTML
<template>
并编写自己的脚本使用它 - 创建一个 Web 组件
- 使用后端语言,或使用像 Nunjucks 这样的语言提前进行处理
- 使用预处理器,例如 Pug
一般来说,我建议在服务器端或构建过程中进行模板化 — 如果没有必要,为什么要修改 DOM 呢?
但让我们暂时忽略这一建议,以下是如何在客户端使用 Handlebars 进行模板化的示例,这样来自原始邮件的朋友就有一个可行的例子,说明它是如何工作的
最简单的解决方案不是应该有一个(唯一)的 ID,例如
然后查找 ID,并在 JavaScript 中用内容填充 innerHTML?
我认为这是 Web 技术复杂性中出现的一个问题。 新手不太可能按照老手(比如你和我的)的顺序学习基本构建块;HTML、然后 CSS、然后 JavaScript、然后 js 代码片段、框架等。
由于互联网上知识的覆盖范围如此之大,新手对 Web 开发的第一印象可能是 React / Vue / Svelte / 等等。 模板问题就是一个很好的例子,它说明了现实与期望之间的差距。
@David King:感谢你的评论。 你的评论准确而简洁地概括了要点,我对此表示赞赏。
有两个想法
1. “emergent” 这个词用得准确吗?
2. 这个问题是否仅限于“Web 技术”的复杂性?
回顾我自己的经验,我认为现在的入门门槛要低很多,学习事物顺序的机会仍然很多(例如,HTML Goodies、MDN、You Don’t Know JS)。
23年前我刚开始学习的时候,这个问题困扰着我,但当时还没有 Google、YouTube、StackOverflow、Quota 等等,这些平台上有很多人解释如何去做事情。
另外,data.js 脚本需要放在 Tag 的正上方,否则
document.querySelector("div")
将返回 null,因为该元素在那时不存在。
以前从未听说过 eleventy 或 html 模板标签。 感谢你的建议,我将深入研究一下 :)。
放在
</body>
标签的正上方 *很棒且信息丰富,感谢分享。
冒着遗漏要点的风险(毫无疑问,最初的用例比显示的要复杂),我认为可以公平地说,有时直接编写 HTML 也是可以的
我认为,从安全性和性能的角度来看,
.textContent
比.innerHTML
更好。不知何故,你对任何新手来说,使用 Handlebars 中更抽象的名称(例如
source
、context
,甚至是template
或html
- 或者类似的东西)会让事情变得更难,更不用说你用“const”而不是“var”来处理它们了 :)。可能只是我个人对命名约定有意见,但这确实会让新手学习曲线变得更陡峭。
让我解释一下原因
- 首先,一个好的解决方案是确实使用一行代码,但使用更简单直观的代码,比如 jQuery,这样可以慢慢地向新手介绍 getter 和 setter 的概念[获取值,然后设置数据的显示]。 也就是说,很明显,名为
source
的实际内容不是 innerHTML - 因为它实际上是数据的目标,而不是它的源泉
。 innerHTML 正在渴望着
数据,即使来自不同的来源,如果可能的话,所以它是数据的消费者,是所有内容的终点。jQuery 的一行代码可以是
比使用难看的驼峰命名法 querySelector 更直观(再次,对于一个实际上不是
选择一些查询
而是选择一个项目的东西来说,这是一个糟糕的命名选择,对吧?…)我不打算在这里写下 jQuery 的代码,因为问题不在于写代码,而在于设计编码方法的简单性 - 也是因为这里的读者比新手水平高很多。
- 一次又一次,披头士乐队告诉人们,我们所需要的就是爱。 在编码中,我们所需要的就是好名字 - 为了让语言更易于理解和阅读。 我从最谦虚的(甚至不是编程语言本身)HTML 中汲取了教训 :) 尽管不像 JavaScript 那样处理复杂性,它却有着天才的想法,那就是让事物
语义化
,以使每个人免受糟糕的习语的困扰。 我们能否在这个案例中使用语义化? 当然可以。- 另一个糟糕的命名方式是使用
template
来表示来自方法的内容 - 方法本身就是一个函数 - 并将其存储在一个容器(变量)中。 再次,这可能对新手来说太难了 :)。说 "const template =…" 某种程度上会让读者做好准备,认真寻找是否存在特定的模式,对吧?毕竟模板就像一个模式,拥有精确的形状或某种材质!然而,他看到的却是一片空白,只是一个空洞的词语,实际上是一种引用(编译某样东西,明白吗?),意思是“去某个地方处理某样东西”,所以(开玩笑地说)也许在你一路走来的时候,你也许会理解那里发生了什么。就像说 `馅饼的味道只有在你吃掉它之后才知道` :D … 那里没有真正的模板,什么都没有,只有一句行动号召(编译一个嗡嗡声或酒吧声)…
我应该继续吗?`context` 这个词又一次被误用了。我最好把它改名为 `origin`,因为它仅仅指的是一组数据,没什么比这更重要的了。Origin 同时也意味着新鲜和有用 - 就像我们可能从各种来源(后端、API,你随便说)中获取的数据一样。相反,`context` 通常是指`事情发生` 的空间,`孩子` 数据“成长”到成年并最终使用的那片欢乐的社区 - 所以它不是数据本身 :(。
最后一行加剧了所有问题:它没有叫 `result`,而是叫 `html`。可怕的事情不断发生(新手再次惊恐地发现,名为 `template` 的东西是一个函数,而不是一个变量 - 而且它甚至不是一个变量,因为它在上一行就被称为 "const" …)
别误会我,我喜欢 Handlebars 做的事情,但是从一开始,当我在 Postman 中看到它们是如何统治那里的时,我就反对它们愚蠢的命名方式 :D
改变 n-a-m-e-s,是的,你会看到 cOdE 的真正美丽和力量。KISS :) (保持简单,笨蛋) - 对于新手来说,或者对于追求极致性能的程序员来说是 YAGNI ;)
谢谢。
PS 在我的手机上写这条评论,用上面的命名建议重写上面的 JS 代码对我来说是一件苦差事,所以请大家随意在自己的电脑上做这件事。它一定尝起来更好。:) 我希望/希望/这个话题能够引发关于真正核心编程的健康辩论。再次感谢讨论的主持人!感谢你的工作。
Michael Jackson 在我们开发 Mustache 的时候发现,模板总是试图重新创建 javascript,并迫使用户学习新的语法。 https://twitter.com/mjackson/status/803808828634472448
JSX 很棒,因为它允许你用 javascript 编写类似模板的语法,但它的主要问题是它迫使你使用很多笨拙的模式,比如短路。
我个人认为,理想情况下它应该更像 PHP 模板,你可以在其中用原生 JS 编写你的逻辑代码,并在这些代码块之间插入 HTML。没有框架,只有 javascript 和 html。
Alpine.js 非常棒。它是内联 JavaScript,语法是模仿 vue.js,但没有使用 shadow DOM。模板化用起来会很简单
如果你可以的话,在服务器端做模板化是个好建议。在这种情况下,你可以尝试 Hypertag (http://hypertag.io/),一种受 Python 启发的文档生成语言,具有简洁的基于缩进的语法和许多高级功能:原生自定义标签、DOM 操作、复合表达式……快速入门: https://github.com/mwojnars/hypertag