javascript - 在 Eleventy 中执行小型客户端 JavaScript 的最佳方式是什么?

标签 javascript static-site eleventy

问题

我想向我的 Eleventy 网站添加一小段客户端 JavaScript。我似乎无法使用 Eleventy 访问 document.,这意味着我无法访问元素并监听它们的事件。 不起作用的示例:

const formElement = document.querySelector("form")

我从 Eleventy 收到的错误消息:

ReferenceError: document is not defined

问题

我如何使用 Eleventy 来监听文档元素更改并进行页面更改?

例子:

formElement.addEventListener("change", function () {
    // Update nearby paragraph element based on form value
});

我的真实场景:我想让一个段落元素显示 form 的哪个 input type="radio" 具有值 已检查

到目前为止的方法

我在/data 中有一个名为 fruits.json 的文件:

{
  "items": [
    {
      "name": "Apple"
    },
    {
      "name": "Banana"
    },
    {
      "name": "Strawberry"
    },
    {
      "name": "Mango"
    },
    {
      "name": "Peach"
    },
    {
      "name": "Watermelon"
    },
    {
      "name": "Blueberry"
    }
  ]
}

还有/_includes/layouts 中的一个 HTML 文件基于我的 base.html 文件:

{% extends "layouts/base.html" %}

{% block content %}

<form>
 {% for item in fruits.items %}
 {# Create a radio button for each, with the first one checked by default #}
 <input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
    <label for="{{ item.name | slug }}">{{ item.name }}</label>
 {% endfor %}

{% set selectedFruit = helpers.getSelectedFruit() %}
<p>Currently selected item from above is: {{ selectedFruit }}</p>
</form>

{% endblock %}

请注意,名为 selectedFruit 的变量已分配给辅助函数:

{% set selectedScreen = helpers.getSelectedScreen() %}

getSelectedScreen() 函数如下所示:

getSelectedScreen() {
    const formEl = document.querySelector("form")
    console.log(formEl)
}

除了无法使用 .document 之外,我觉得这种方法可能在其他方面“违背了 Eleventy 的原则”,即静态站点生成器:

  • 脚本在文档中间被调用
  • 脚本是一次性的并且脱离了它的上下文

我想知道我是否一开始就处理了这个错误,或者我是否只需要做一些事情来允许 .document 访问。

最佳答案

这里存在一些误解 — JavaScript 代码最重要的区别在于它是在构建时还是在客户端在运行时执行。

Eleventy 核心以及您的 .eleventy.js 配置文件是用 JavaScript 编写的,它在构建步骤中执行一次,即在生成静态站点时执行一次。这发生在 NodeJS 环境中,而不是浏览器中,这就是没有 document 变量和 DOM 的原因。

如果您想动态更改您网站上的某些内容以响应用户交互,您需要编写一个单独的 JavaScript 文件,该文件被复制到静态网站的输出目录中。然后,您可以将其包含在静态网站的 HTML 模板中,以便在部署网站后正常页面访问期间包含它。

首先,修改您的模板,只为您的 JavaScript 函数生成一个占位符元素,以便稍后添加文本:

{% extends "layouts/base.html" %}

{% block content %}

<form id="fruits-form">
 {% for item in fruits.items %}
 {# Create a radio button for each, with the first one checked by default #}
 <input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
    <label for="{{ item.name | slug }}">{{ item.name }}</label>
 {% endfor %}

  <p id="selected-fruits-output"></p>
</form>

{% endblock %}

然后,创建一个 JavaScript 文件来响应表单上的更改事件:

// fruit-form.js
const fruitForm = document.getElementById('fruits-form');
const formOutput = document.getElementById('selected-fruits-output');
fruitForm.addEventListener('change', e => {
    // update the formOutput with the list of selected fruits
});

现在您需要使用Passthrough file copy 确保将此javascript 文件复制到您的输出目录中。 :

eleventyConfig.addPassthroughCopy("path/to/fruit-form.js");

最后,确保在您的 HTML 模板中包含脚本元素(确保路径是上面指定的输出的绝对路径):

{# layouts/base.html #}
<script src="/path/to/fruit-form.js" defer></script>

现在它应该可以正常工作了。一般而言,请务必了解构建时和运行时 JavaScript 之间的区别,以便您可以决定在不同情况下哪种效果最好。

关于javascript - 在 Eleventy 中执行小型客户端 JavaScript 的最佳方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64981081/

相关文章:

javascript - 使用 formcontrol 验证 md-datepicker

javascript - 在 Google Maps API v3 中获取自定义图 block 的中心 LatLng 点

swiper.js - SwiperJS 不显示下一个/上一个图标,但区域是可点击的

nunjucks - 11ty 标题中的页面 &lt;style&gt;

javascript - 已加载另一出版物后订阅另一出版物 | React-Meteor

python - Django: AttributeError: 'NoneType' 对象没有属性 'split'

go - 如何在Hugo网站中更改默认的url “/posts/”路由?

javascript - gatsby-source-wordpress : localFile field null on images in ACF fields on netlify deploy

javascript - 删除 JS 嵌套对象数组中任意级别的项目