getElementsByTagName在脚本位于/body之前仍返回undefined。

huangapple go评论74阅读模式
英文:

getElementsByTagName returns undefined even with the script before /body

问题

我是一个完全不懂JavaScript的初学者,我完全被卡住了。我尝试通过调整在教程中找到的代码来创建一个搜索栏过滤系统。目标是能够按电影的名称、导演或发行年份进行过滤。

每个电影的信息分别在<h1><h2><h3>标签之间。排序是通过getElementsByTagName完成的,并且对导演和发行年份正常工作,但只要我添加电影标题,就什么都不起作用了。

从我在Firefox中看到的情况来看,导致问题的原因是我存储电影名称的变量未定义(Uncaught TypeError: a is undefined)。经过一些研究,我了解到此错误在页面加载前运行脚本时出现,因此我将其放置在</body>之前,但问题仍然存在。

我想理解我的代码有什么问题。

function myFunction() {
  // 声明变量
  var input, filter, ul, li, a, b, c, i, title, director, date;
  input = document.getElementById('myInput');
  filter = input.value.toUpperCase();
  ul = document.getElementById("myUL");
  li = ul.getElementsByTagName('li');

  // 遍历所有列表项,并隐藏不匹配搜索查询的项
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("h1")[0];
    b = li[i].getElementsByTagName("h2")[0];
    c = li[i].getElementsByTagName("h3")[0];
    title = a.textContent || a.innerText;
    director = b.textContent || b.innerText;
    date = c.textContent || c.innerText;
    if (title.toUpperCase().indexOf(filter) > -1 || director.toUpperCase().indexOf(filter) > -1 || date.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = "";
    } else {
      li[i].style.display = "none";
    }
  }
}
<ul id="myUL" class="gallery container">
  <li>
    <div class="overlay"></div>
    <div class="info">
      <a href="#" class="btn"><img src="example.jpg"></a>
      <div class="description">
        <h1 style="display:none">TITLE</h1>
        <h2>DIRECTOR</h2>
        <h3>DATE</h3>
        <p>
          SYNOPSIS
        </p>
      </div>
    </div>
    <div class="bg-img">
      <img src="example2.jpg">
    </div>
  </li>
</ul>

希望这可以帮助你找到代码中的问题。

英文:

I am a complete beginner in JavaScript and I am completely blocked. I am trying to create a search bar filtering system by adapting a code found in a tutorial. The goal is to be able to filter a list of movies by name, director or year of release.

Each of these information are respectively between tags &lt;h1&gt;, &lt;h2&gt; then &lt;h3&gt;. The sorting is done by getElementsByTagName and works as expected with the director and year of release, but as soon as I add the title of the movies, nothing works anymore.

From what I see in Firefox, the cause being that the variable in which I store the movie name is not defined (Uncaught TypeError: a is undefined). After some research, I was able to read that this error appears when the script is run before the page is loaded, so I placed it just before the /body, but the problem persists.

I would like to understand what is wrong with my code.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function myFunction() {
  // Declare variables
  var input, filter, ul, li, a, b, c, i, title, director, date;
  input = document.getElementById(&#39;myInput&#39;);
  filter = input.value.toUpperCase();
  ul = document.getElementById(&quot;myUL&quot;);
  li = ul.getElementsByTagName(&#39;li&#39;);

  // Loop through all list items, and hide those who don&#39;t match the search query
  for (i = 0; i &lt; li.length; i++) {
    a = li[i].getElementsByTagName(&quot;h1&quot;)[0];
    b = li[i].getElementsByTagName(&quot;h2&quot;)[0];
    c = li[i].getElementsByTagName(&quot;h3&quot;)[0];
    title = a.textContent || a.innerText;
    director = b.textContent || b.innerText;
    date = c.textContent || c.innerText;
    if (title.toUpperCase().indexOf(filter) &gt; -1 || director.toUpperCase().indexOf(filter) &gt; -1 || date.toUpperCase().indexOf(filter) &gt; -1) {
      li[i].style.display = &quot;&quot;;
    } else {
      li[i].style.display = &quot;none&quot;;
    }
  }
}

<!-- language: lang-html -->

&lt;ul id=&quot;myUL&quot; class=&quot;gallery container&quot;&gt;
  &lt;li&gt;
    &lt;div class=&quot;overlay&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;info&quot;&gt;
      &lt;a href=&quot;#&quot; class=&quot;btn&quot;&gt;&lt;img src=&quot;example.jpg&quot;&gt;&lt;/a&gt;
      &lt;div class=&quot;description&quot;&gt;
        &lt;h1 style=&quot;display:none&quot;&gt;TITLE&lt;/h1&gt;
        &lt;h2&gt;DIRECTOR&lt;/h2&gt;
        &lt;h3&gt;DATE&lt;/h3&gt;
        &lt;p&gt;
          SYNOPSIS
        &lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;bg-img&quot;&gt;
      &lt;img src=&quot;example2.jpg&quot;&gt;
    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

<!-- end snippet -->

答案1

得分: 1

以下是您要翻译的内容:

在原帖中,&lt;script&gt;标签位于正确位置。不幸的是,这只是解决方案的一部分。

问题

  • HTML中的&lt;input&gt;在哪里?

  • 为每个类别过滤器添加了复选框:titledirectordate

  • 使用过时的方法,如.getElementsByTagName()在[某些情况下][1]可能会有问题。相反,使用[.querySelectorAll()][2]。

  • window的“load”事件上调用搜索函数几乎没有意义。页面与用户之间的交互可以在&lt;input id=&quot;find&quot;&gt;&lt;form&gt;上触发的“click”、“input”、“change”或“submit”事件上处理。在示例中,一个&lt;form&gt;包裹了所有元素,并注册了[“submit”事件][3]。

  • .textContent.innerText几乎是[相同的][4],使用其中之一即可。

  • &lt;h1&gt;&lt;h6&gt;是标题,应用于按重要性排序的内容的标题。页面应只使用一个&lt;h1&gt;。将&lt;h1&gt;&lt;h2&gt;&lt;h3&gt;添加到每个&lt;li&gt;不仅令人讨厌,而且在语义上也很糟糕。使用CSS来调整font-sizefont-weight

示例中有注释的详细信息

注意:源代码的某些部分带有仅供演示目的的标签,这不是必需的,只是用来生成&lt;ul&gt;的内容。

// 仅供演示目的
const data = [{
  "title": "Plain Dirty (a.k.a. Briar Patch)",
  "director": "Jodi MacEllen",
  "date": "7/16/2018"
}, {
  "title": "Cake",
  "director": "Faber Pude",
  "date": "5/3/2012"
}, {
  "title": "Exit Smiling",
  "director": "Bryant Whytock",
  "date": "1/26/1972"
}, {
  "title": "Mission: Impossible III",
  "director": "Allison Kayzer",
  "date": "5/14/1986"
}, {
  "title": "Hollywood Between Paranoia and Sci-Fi. The Power of Myth",
  "director": "Isacco Yoell",
  "date": "3/14/1980"
}, {
  "title": "Barabbas",
  "director": "Humfrid Scandrett",
  "date": "6/12/2018"
}, {
  "title": "Stolen (Stolen Lives)",
  "director": "Harv Ginman",
  "date": "2/19/2014"
}, {
  "title": "Casper",
  "director": "Ferne Nester",
  "date": "9/20/2011"
}, {
  "title": "Journey to the Beginning of Time",
  "director": "Dodi Chaster",
  "date": "12/4/2014"
}, {
  "title": "Home Run",
  "director": "Nonna Bugler",
  "date": "5/4/1972"
}];

// 引用&lt;ul&gt;
const list = document.querySelector("ul");

// 仅供演示目的
data.forEach(movie => {
  const li = `<li><i>${movie.title}</i> - 
              <b>${movie.director}</b> - 
              <time>${movie.date}</time></li>`;
  list.insertAdjacentHTML("beforeend", li);
});

// 引用&lt;form&gt;
const F = document.forms.main;
// 引用所有&lt;input&gt;和&lt;fieldset&gt;
const fc = F.elements;
// 引用&lt;input id=&quot;find&quot;&gt;
const find = fc.find;
// 将所有[name=&quot;chx&quot;]的HTMLCollection转换为数组
const filters = Array.from(fc.chx);
// 将所有&lt;li&gt;转换为NodeList,然后转换为数组
const items = Array.from(document.querySelectorAll("li"));
// 注册&lt;form&gt;到“submit”事件
F.onsubmit = searchList;

// 事件处理程序传递事件对象
function searchList(event) {
  // 阻止&lt;form&gt;重定向页面
  event.preventDefault();
  /**
   * 从&lt;input id=&quot;find&quot;&gt;获取用户搜索词
   * 将字符串转换为数组。
   */
  const keywords = find.value.toLowerCase().split(" ");
  // 隐藏所有&lt;li&gt;
  items.forEach(li => li.style.display = "none");
  // 获取每个已选复选框的索引号数组
  const checked = filters.flatMap((chx, idx) => chx.checked ? idx : []);
  /**
   * 对于每个&lt;li&gt;...
   * ...从&lt;li&gt;中的&lt;i&gt;、&lt;b&gt;和&lt;time&gt;中获取文本的数组...
   * ...创建一个仅包含与已检查数组中的数字匹配的索引的文本的数组,然后将其转换为字符串...
   * ...如果搜索词中的一个也在当前&lt;li&gt;的文本中...
   * ...显示&lt;li&gt;
   */
  items.forEach(li => {
    let text = Array.from(li.children).map(ele => ele.textContent.toLowerCase());
    let filtered = text.filter((txt, cnt) => checked.includes(cnt)).join("");

    if (keywords.some(word => filtered.includes(word))) {
      li.style.display = "list-item";
    }
  });
}
:root {
  font: 2ch/1.15 "Segoe UI";
}

fieldset {
  padding-right: 20px;
}

input {
  font: inherit;
  height: 3.5ex;
}

#find {
  width: 80%;
  margin: 15px 0 0 25px;
}

[type="submit"] {
  font-variant: small-caps;
  cursor: pointer;
}

menu,
label {
  display: flex;
  align-items: center;
  margin-left: 15px;
}

menu

<details>
<summary>英文:</summary>

In the OP, the `&lt;script&gt;` tag is in the correct place. Unfortunately, that was only a part of the solution.

Problems
-

- Where&#39;s the `&lt;input&gt;` in the HTML?

- Added a checkbox for each category filter: `title`, `director`, and `date`.

- Using antiquated methods such as `.getElementsByTagName()` can be problematic under [certain circumstances][1]. Instead, use [`.querySelectorAll()`][2]. 

- Calling the search function on &quot;load&quot; event of `window` makes very little sense. The interaction between the page and user can be handled on a &quot;click&quot;, &quot;input&quot;, &quot;change&quot;, or &quot;submit&quot; event triggered on either the `&lt;input id=&quot;find&quot;&gt;` or a `&lt;form&gt;`. In the example, a `&lt;form&gt;` is wrapped around all of the elements and is registered to the [&quot;submit&quot; event][3]. 

- `.textContent` and `.innerText` are [almost identical][4], use one or the other.

- `&lt;h1&gt;` thru `&lt;h6&gt;` are headings and should be used for titles of content organized in the order of importance. Only a single `&lt;h1&gt;` should be used for a page. Adding `&lt;h1&gt;`, `&lt;h2&gt;`, and `&lt;h3&gt;` to each `&lt;li&gt;` is not only an eyesore but it&#39;s semantically horrible as well. Use CSS to adjust `font-size` and `font-weight` instead.

**Details are commented in example**

**Note:** There are parts of the source labeled with *For demo purposes*, which is not required and is there just to generate the content for the `&lt;ul&gt;`.

&lt;!-- begin snippet: js hide: false console: true babel: false --&gt;

&lt;!-- language: lang-js --&gt;

    // For demo purposes
    const data = [{
      &quot;title&quot;: &quot;Plain Dirty (a.k.a. Briar Patch)&quot;,
      &quot;director&quot;: &quot;Jodi MacEllen&quot;,
      &quot;date&quot;: &quot;7/16/2018&quot;
    }, {
      &quot;title&quot;: &quot;Cake&quot;,
      &quot;director&quot;: &quot;Faber Pude&quot;,
      &quot;date&quot;: &quot;5/3/2012&quot;
    }, {
      &quot;title&quot;: &quot;Exit Smiling&quot;,
      &quot;director&quot;: &quot;Bryant Whytock&quot;,
      &quot;date&quot;: &quot;1/26/1972&quot;
    }, {
      &quot;title&quot;: &quot;Mission: Impossible III&quot;,
      &quot;director&quot;: &quot;Allison Kayzer&quot;,
      &quot;date&quot;: &quot;5/14/1986&quot;
    }, {
      &quot;title&quot;: &quot;Hollywood Between Paranoia and Sci-Fi. The Power of Myth&quot;,
      &quot;director&quot;: &quot;Isacco Yoell&quot;,
      &quot;date&quot;: &quot;3/14/1980&quot;
    }, {
      &quot;title&quot;: &quot;Barabbas&quot;,
      &quot;director&quot;: &quot;Humfrid Scandrett&quot;,
      &quot;date&quot;: &quot;6/12/2018&quot;
    }, {
      &quot;title&quot;: &quot;Stolen (Stolen Lives)&quot;,
      &quot;director&quot;: &quot;Harv Ginman&quot;,
      &quot;date&quot;: &quot;2/19/2014&quot;
    }, {
      &quot;title&quot;: &quot;Casper&quot;,
      &quot;director&quot;: &quot;Ferne Nester&quot;,
      &quot;date&quot;: &quot;9/20/2011&quot;
    }, {
      &quot;title&quot;: &quot;Journey to the Beginning of Time&quot;,
      &quot;director&quot;: &quot;Dodi Chaster&quot;,
      &quot;date&quot;: &quot;12/4/2014&quot;
    }, {
      &quot;title&quot;: &quot;Home Run&quot;,
      &quot;director&quot;: &quot;Nonna Bugler&quot;,
      &quot;date&quot;: &quot;5/4/1972&quot;
    }];

    // Reference &lt;ul&gt;
    const list = document.querySelector(&quot;ul&quot;);

    // For demo purposes
    data.forEach(movie =&gt; {
      const li = `&lt;li&gt;&lt;i&gt;${movie.title}&lt;/i&gt; - 
                  &lt;b&gt;${movie.director}&lt;/b&gt; - 
                  &lt;time&gt;${movie.date}&lt;/time&gt;&lt;/li&gt;`;
      list.insertAdjacentHTML(&quot;beforeend&quot;, li);
    });

    // Reference the &lt;form&gt;
    const F = document.forms.main;
    // Reference all &lt;input&gt; and &lt;fieldset&gt;
    const fc = F.elements;
    // Reference &lt;input id=&quot;find&quot;&gt;
    const find = fc.find;
    // Make HTMLCollection of all [name=&quot;chx&quot;] into an array
    const filters = Array.from(fc.chx);
    // Make NodeList of all &lt;li&gt; then into an array
    const items = Array.from(document.querySelectorAll(&quot;li&quot;));
    // Register &lt;form&gt; to &quot;submit&quot; event
    F.onsubmit = searchList;

    // Event handler passes Event Object
    function searchList(event) {
      // Stop &lt;form&gt; from redirecting page
      event.preventDefault();
      /**
       * Get user search words from &lt;input id=&quot;find&quot;&gt;
       * Convert string into an array.
       */
      const keywords = find.value.toLowerCase().split(&quot; &quot;);
      // Hide all &lt;li&gt;
      items.forEach(li =&gt; li.style.display = &quot;none&quot;);
      // Get an array of index numbers of each checked checkbox
      const checked = filters.flatMap((chx, idx) =&gt; chx.checked ? idx : []);
      /**
       * For each &lt;li&gt;...
       * ...Make an array (text) of text from &lt;i&gt;, &lt;b&gt;, and &lt;time&gt; in &lt;li&gt;...
       * ...Make an array (filtered) of texts of only index that 
       * match the numbers in checked array and convert it into a string...
       * ...If one of the search words is also in the text of the current &lt;li&gt;...
       * ...show the &lt;li&gt;
       */
      items.forEach(li =&gt; {
        let text = Array.from(li.children).map(ele =&gt; ele.textContent.toLowerCase());
        let filtered = text.filter((txt, cnt) =&gt; checked.includes(cnt)).join(&quot;&quot;);

        if (keywords.some(word =&gt; filtered.includes(word))) {
          li.style.display = &quot;list-item&quot;;
        }
      });
    }

&lt;!-- language: lang-css --&gt;

    :root {
      font: 2ch/1.15 &quot;Segoe UI&quot;;
    }

    fieldset {
      padding-right: 20px;
    }

    input {
      font: inherit;
      height: 3.5ex;
    }

    #find {
      width: 80%;
      margin: 15px 0 0 25px;
    }

    [type=&quot;submit&quot;] {
      font-variant: small-caps;
      cursor: pointer;
    }

    menu,
    label {
      display: flex;
      align-items: center;
      margin-left: 15px;
    }

    menu {
      list-style: none;
      margin-left: -15px;
    }

&lt;!-- language: lang-html --&gt;

    &lt;form id=&quot;main&quot;&gt;
      &lt;fieldset&gt;
        &lt;legend&gt;Search by keywords delimited by a space&lt;/legend&gt;
        &lt;input id=&quot;find&quot; placeholder=&quot;x the 2018&quot; type=&quot;search&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Find&quot;&gt;
        &lt;menu&gt;Filters:&amp;nbsp;
          &lt;label&gt;&lt;input name=&quot;chx&quot; type=&quot;checkbox&quot; checked&gt; Title &lt;/label&gt;
          &lt;label&gt;&lt;input name=&quot;chx&quot; type=&quot;checkbox&quot; checked&gt; Director &lt;/label&gt;
          &lt;label&gt;&lt;input name=&quot;chx&quot; type=&quot;checkbox&quot; checked&gt; Date &lt;/label&gt;
        &lt;/menu&gt;
        &lt;ul&gt;&lt;/ul&gt;
      &lt;/fieldset&gt;
    &lt;/form&gt;

&lt;!-- end snippet --&gt;


  [1]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
  [2]: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
  [3]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit_event
  [4]: https://www.microfocus.com/documentation/silk-test/200/en/silktestworkbench-help-en/SILKTEST-21EEFF3F-DIFFERENCEBETWEENTEXTCONTENTSINNERTEXTINNERHTML-REF.html

</details>



# 答案2
**得分**: 0

你可以在代码中添加 `window.onload` 来调用你的函数这意味着只有在页面加载完成后才会触发你的函数

```javascript
window.onload = function() {
  myFunction();
};

function myFunction() {
  // 声明变量
  var input, filter, ul, li, a, b, c, i, title, director, date;
  ul = document.getElementById("myUL");
  li = ul.getElementsByTagName('li');

  // 循环遍历所有列表项,并隐藏不匹配搜索查询的项
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("h1")[0];
    b = li[i].getElementsByTagName("h2")[0];
    c = li[i].getElementsByTagName("h3")[0];
    title = a.textContent || a.innerText;
    director = b.textContent || b.innerText;
    date = c.textContent || c.innerText;
    console.log(title, director, date);

    if (title.toUpperCase().indexOf(filter) > -1 || director.toUpperCase().indexOf(filter) > -1 || date.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = "";
    } else {
      li[i].style.display = "none";
    }
  }
}
<ul id="myUL" class="gallery container">
  <li>
    <div class="overlay"></div>
    <div class="info">
      <a href="#" class="btn"><img src="https://picsum.photos/200"></a>
      <div class="description">
        <h1 style="display:none">TITLE</h1>
        <h2>DIRECTOR</h2>
        <h3>DATE</h3>
        <p>
          SYNOPSIS
        </p>
      </div>
    </div>
    <div class="bg-img">
      <img src="https://picsum.photos/200">
    </div>
  </li>
</ul>

这是你提供的代码的翻译部分。

英文:

you could add windoe.onload to call your function, meaning only when page is loaded your function will fire.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

window.onload = function() {
myFunction();
};
function myFunction() {
// Declare variables
var input, filter, ul, li, a, b, c, i, title, director, date;
ul = document.getElementById(&quot;myUL&quot;);
li = ul.getElementsByTagName(&#39;li&#39;);
// Loop through all list items, and hide those who don&#39;t match the search query
for (i = 0; i &lt; li.length; i++) {
a = li[i].getElementsByTagName(&quot;h1&quot;)[0];
b = li[i].getElementsByTagName(&quot;h2&quot;)[0];
c = li[i].getElementsByTagName(&quot;h3&quot;)[0];
title = a.textContent || a.innerText;
director = b.textContent || b.innerText;
date = c.textContent || c.innerText;
console.log(title, director, date);
if (title.toUpperCase().indexOf(filter) &gt; -1 || director.toUpperCase().indexOf(filter) &gt; -1 || date.toUpperCase().indexOf(filter) &gt; -1) {
li[i].style.display = &quot;&quot;;
} else {
li[i].style.display = &quot;none&quot;;
}
}
}

<!-- language: lang-html -->

&lt;ul id=&quot;myUL&quot; class=&quot;gallery container&quot;&gt;
&lt;li&gt;
&lt;div class=&quot;overlay&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;info&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;btn&quot;&gt;&lt;img src=&quot;https://picsum.photos/200&quot;&gt;&lt;/a&gt;
&lt;div class=&quot;description&quot;&gt;
&lt;h1 style=&quot;display:none&quot;&gt;TITLE&lt;/h1&gt;
&lt;h2&gt;DIRECTOR&lt;/h2&gt;
&lt;h3&gt;DATE&lt;/h3&gt;
&lt;p&gt;
SYNOPSIS
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;bg-img&quot;&gt;
&lt;img src=&quot;https://picsum.photos/200&quot;&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月21日 23:36:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76300669.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定