如何通过 div 数组使用 click 事件进行迭代
我希望单击时出现文本部分并消失。
在第一次点击之前,您只能看到横幅,还没有经文。在第一个单击第一节时,出现第一节经文,第二次单击第二节出现第二节,以代替第一个经文,依此类推。
我试图通过隐藏元素,将它们放在数组中,并在称为函数的次数时将其显示为符合经文的索引时,将它们显示为实现。
我是JavaScript的新手,不明白引发的例外。如果我尝试在线检查我的代码,那么当o尝试通过单击网站来调用该功能时,我会得到此例外:
Uncaught TypeError: Cannot read properties of null (reading 'style')
这是我的代码到目前为止:
const text = document.querySelector(".banner")
document.addEventListener('click', myFunction);
const verse1 = document.querySelector(".verse1")
const verse2 = document.querySelector(".verse2")
const verse3 = document.querySelector(".verse3")
const verse4 = document.querySelector(".verse4")
const verse5 = document.querySelector(".verse5")
const verses = [verse1, verse2, verse3, verse4, verse5]
let versesLength = verses.length;
function myFunction() {
for (let i = 0; i < versesLength; i++) {
text.innerHTML = verses[i].style.display = 'block';
}
}
<div class="banner">
<script src="main.js"></script>
<img src="files/SomeLogo.jpg" alt="We are still building on our Website:-)">
</div>
<div id="verses">
<div class="verse1" style="display: none">Lorem Ipsum</div>
<div class="verse2" style="display: none">Lorem Ipsum2</div>
<div class="verse3" style="display: none">Lorem Ipsum3</div>
<div class="verse4" style="display: none">Lorem Ipsum4</div>
<div class="verse5" style="display: none">Lorem Ipsum5</div>
</div>
我被卡住了,在过去的几个小时内点击了类似的问题。事先感谢您的任何帮助
I want text parts to appear, and disappear, on click.
Before the first click you can only see the banner, and no verses yet; on the first click the first verse appears, on second click the second verse appears in place of the first, and so on.
I am trying to achieve this with hiding the elements, placing them in an array, and let them display when the number of times the function gets called fits the index of the verse.
I am new to JavaScript, and don't understand the exceptions thrown. If i try to inspect my code online, I get this Exception when O try to call the function by clicking on the website:
Uncaught TypeError: Cannot read properties of null (reading 'style')
This is my code so far:
const text = document.querySelector(".banner")
document.addEventListener('click', myFunction);
const verse1 = document.querySelector(".verse1")
const verse2 = document.querySelector(".verse2")
const verse3 = document.querySelector(".verse3")
const verse4 = document.querySelector(".verse4")
const verse5 = document.querySelector(".verse5")
const verses = [verse1, verse2, verse3, verse4, verse5]
let versesLength = verses.length;
function myFunction() {
for (let i = 0; i < versesLength; i++) {
text.innerHTML = verses[i].style.display = 'block';
}
}
<div class="banner">
<script src="main.js"></script>
<img src="files/SomeLogo.jpg" alt="We are still building on our Website:-)">
</div>
<div id="verses">
<div class="verse1" style="display: none">Lorem Ipsum</div>
<div class="verse2" style="display: none">Lorem Ipsum2</div>
<div class="verse3" style="display: none">Lorem Ipsum3</div>
<div class="verse4" style="display: none">Lorem Ipsum4</div>
<div class="verse5" style="display: none">Lorem Ipsum5</div>
</div>
I am stuck, and clicked through similar questions for the last hours. Thanks in advance for any help
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
没有更改HTML中的任何内容,您可以在JavaScript中执行类似的操作
without changing anything in the HTML, you can do something like this in javascript
您可以通过为所有 verse 元素指定相同的类来消除对数组的需求:
verse
。我们可以使用querySelectorAll
< 来获取它们/a>.为每节经文添加数据属性来识别它们。
为了限制全局变量的数量,我们可以使用闭包 - 在
addEventListener
中,我们调用handleClick
函数来初始化计数,然后返回一个函数将被分配给侦听器。这是一个闭包。它维护一个外部词法环境(即变量)的副本,在返回时可以使用该副本。其他文档
模板/字符串文字< /p>
classList
You can remove the need for an array by giving all the verse elements the same class:
verse
. We can grab them withquerySelectorAll
.Add a data attribute to each verse to identify them.
In order to limit the number of global variables we can use a closure - in the
addEventListener
we call thehandleClick
function which initialises the count, and then returns a function that will be assigned to the listener. This is a closure. It maintains a copy of its outer lexical environment (ie variables) that it can use when it's returned.Additional documentation
Template/string literals
classList
这应该做到这一点:
This should make it:
修复错误
由于您尝试访问 null 的属性,因此会出现“无法读取 null 的属性”错误。您的数组包含空值,因为您在浏览器将元素插入其 DOM 之前查询了这些元素。
浏览器解析 HTML 的方式与您阅读 HTML 的方式相同:从左到右,从上到下。
如果浏览器遇到常规
元素,它会停止解析并首先执行 JavaScript。当然,某些元素可能在 DOM 中尚不可用。
有多种方法可以推迟脚本执行:
defer
到:将在 DOM 完全构建后执行。
type="module"
到:与
defer
类似,但也会使您的代码被视为 JS 模块。这也将使您的代码在严格模式下运行。DOMContentLoaded
:与defer
类似,但封装在 JS 文件中。load
:与DOMContentLoaded
类似,但还会等待所有资源(例如图像、视频)加载完毕。 首选DOMContentLoaded
(如果适用)。移动到 HTML 底部:实际上类似于
defer
。带有defer
的脚本仍将在底部的脚本之后加载。最简单的解决方案是使用
defer
,这样您就不必更改 JS 代码:顺便说一句:不要被 StackOverflow 代码片段所迷惑;使用现场片段时,代码的
会移至 HTML 的底部!
特点!
变量的生命周期
JS 中的变量只有在使用时才会持续存在。
使用在函数外部声明的变量将创建一个闭包 围绕你的函数和变量。这意味着,只要使用该变量的函数存在,该变量就会持续存在:
这意味着,要让用于“跟踪要显示的经文”的变量持续存在,必须在外部声明它你的职能。
显示和隐藏!
通过计算前一节的索引和下一个要显示的节的索引,我们只需要保留一个计数器。对于两个计数器,如果我们不正确处理它们,它们可能会不同步。
在我们的例子中,用户(或者更确切地说,他们的点击)将扮演循环的角色。它们会导致我们的点击处理程序(函数)偶尔运行,此时我们必须交换诗句。
交换诗句可以通过多种方式完成,但我们将坚持您的“内联样式”方式:(最终代码)
改进?!
不需要变量
versesLength
;您可以直接将其每次出现替换为 verses.length 。它不会对原始名称进行改进,并且如果不与原始变量同步,则会成为错误的又一个潜在来源。正确使用
class
和id
目前,您的诗句使用
class
就好像它是id
一样;他们各自使用不同的类。这并没有错,但从语义上讲,我会使用 id 来达到此目的。要有效地使用
class
属性,您应该为每节经文指定类verse
。这样,您可以通过 JS 更轻松地选择它们(请参阅下一节)。更容易获取元素
与编码世界中的一切一样,问题有多种解决方案。您以相当乏味的方式解决了获取元素的问题,但还有其他选择:(非详尽列表)
document.querySelectorAll()
。文档。 getElementsByClassName()
。Element.children
。你可能已经注意到我是如何获得所有诗句的。事实上,
verses
(在最终代码中)甚至没有引用数组,而是引用HTMLCollection
。它与数组非常相似,不同之处在于它会根据更改实时更新:隐藏的替代方法
以下是隐藏元素的方法:
hidden
。对于小的样式更改,我也会使用内联样式。但对于仅隐藏元素,我会使用
hidden
属性。此外,还有多种隐藏元素的 CSS 方法:
display: none
:将隐藏元素,就好像它不存在一样。opacity: 0
:将通过使其不可见来隐藏该元素;它仍然占用空间,并且仍然应该是辅助功能树(有意见)。position:fixed
和top
、left
等属性将其移至异地:(请勿这样做。)将从视觉上将元素移出现场。它仍然是可访问性树的一部分,并且仅适用于具有预期书写方向的语言(例如,它不适用于 从右到左语言)。
width
、height
、margin
、padding
和border
设置为 0:将隐藏该元素仅在视觉上;它仍然是可访问性树的一部分,并且将停止 margin崩溃。 仅屏幕阅读器类将此用于非视觉元素,非常有用。Fixing the error
The "Cannot read properties of null" error occurs because you try to access the properties of null. Your array holds nulls because you queried for the elements before the browser has inserted them into its DOM.
The browser parses the HTML the same way you would read it: From left to right, and top to bottom.
If the browser encounters a regular
<script>
element, it halts parsing and first executes the JavaScript. Naturally, some elements may not yet be available in the DOM.There are multiple ways to defer script execution:
defer
to<script>
: Will execute once the DOM is fully built.type="module"
to<script>
: Similar todefer
, but will also make your code be treated as a JS module. This will also make your code run in strict mode.DOMContentLoaded
: Similar todefer
, but encapsulated in your JS-file.load
: Similar toDOMContentLoaded
, but will additionally wait until all resources (e.g. images, videos) have loaded. PreferDOMContentLoaded
if applicable.<script>
to the bottom of the HTML: Effectively likedefer
. Scripts withdefer
will still load after scripts at the bottom.The simplest solution would be to use
defer
, as with it you wouldn't have to change your JS code:By the way: Don't be fooled by the StackOverflow snippets; when using the on-site snippets, the
<script>
for the code is moved to the bottom of the HTML!The feature!
Variable lifetimes
Variables in JS only persist for as long as they are used.
Using a variable that is declared outside a function will create a closure around your function and variable. That means, that variable will persist for as long as the function exists that uses it:
This means, to have the variable for "keeping track of what verse to show" persist, it has to be declared outside your function.
Show and hide!
By calculating the previous verse's index with the index of the next-to-show verse, we only have to keep one counter. With two counters, they might get out of sync if we don't handle them correctly.
In our case, the user (or rather, their clicks) will play the role of the loop. They will cause our click handler (the function) to run occasionally, at which point we have to swap the verses.
Swapping the verses can be done in many ways, but we'll stick to your "inline style" way: (Final code)
Improvements?!
There is no need for the variable
versesLength
; you can directly replace each of its occurences withverses.length
. It doesn't improve on the original name, and is one more potential source for bugs if not synchronized with the original variable.Correctly use
class
andid
Currently, your verses use
class
as if it wasid
; they each use a different class. This is not wrong, but semantically I would useid
for this purpose.To use the
class
attribute effectively, you should give each verse the classverse
. This way, you can select them more easily via JS (see next section).Easier getting of elements
As with everything in the coding world, there are many solutions to a problem. You solved getting the elements in a rather tedious way, but there are alternatives: (Non-exhaustive list)
document.querySelectorAll()
.document.getElementsByClassName()
.Element.children
.You may have already noticed how I get all the verses. In fact,
verses
(in the final code) doesn't even reference an array, but anHTMLCollection
. It is very similar to an array, with the exception of it updating live to changes:Alternative way of hiding
Here are ways of hiding the elements:
hidden
.For small style changes I too would use inline styling. But for only hiding elements I would use the
hidden
attribute.Also, there are multiple CSS ways of hiding elements:
display: none
: Will hide the element as if it doesn't exist.opacity: 0
: Will hide the element by making it invisible; it still takes up space, and should still be part of the accessibility tree (opinionated).position: fixed
andtop
,left
, etc. properties: (Please don't.)Will move the element off-site, visually. It will still be part of the accessibility tree, and will only work for languages with the intended writing direction (e.g. it won't work for right-to-left languages).
width
,height
,margin
,padding
andborder
to 0: Will hide the element only visually; it will still be part of the accessibility tree, and will stop margin collapse. Screen-reader only classes use this for non-visual elements, very useful.