【问题标题】:How to declare selectors dynamically in Javascript?如何在 Javascript 中动态声明选择器?
【发布时间】:2019-08-28 20:44:16
【问题描述】:

我有重复的变量声明,我认为可以通过 for 循环对其进行改进,但我的尝试失败了。

我尝试了一个数组的 for 循环声明器,但我的语法不起作用。

我有这个“工作代码”:


<div class ="menu1 item1-1"></div>
<div class ="menu1 item1-2"></div>
<div class ="menu1 item1-3"></div>
<div class ="menu1 item1-4"></div>

<div class ="menu2 item2-1"></div>
<div class ="menu2 item2-2"></div>
<div class ="menu2 item2-3"></div>
<div class ="menu2 item2-4"></div>

<div class ="menu3 item3-1"></div>
<div class ="menu3 item3-2"></div>
<div class ="menu3 item3-3"></div>
<div class ="menu3 item3-4"></div>

<div class ="menu4 item4-1"></div>
<div class ="menu4 item4-2"></div>
<div class ="menu4 item4-3"></div>
<div class ="menu4 item4-4"></div>


var menu1 = document.getElementsByClassName('menu1');
var menu2 = document.getElementsByClassName('menu2');
var menu3 = document.getElementsByClassName('menu3');
var menu4 = document.getElementsByClassName('menu4');

for (let i = 1; i < menu1.length; i++) {

    menu1[i].addEventListener('click', function(){ menu1[i].classList.add("test"); });
}
for (let i = 1; i < menu2.length; i++) {

    menu2[i].addEventListener('click', function(){ menu2[i].classList.add("test"); });
}
for (let i = 1; i < menu3.length; i++) {

    menu3[i].addEventListener('click', function(){ menu3[i].classList.add("test"); });
}
for (let i = 1; i < menu4.length; i++) {

    menu4[i].addEventListener('click', function(){ menu4[i].classList.add("test"); });
}


我试图减少它是这样的:


var MENU = [];

for (let i = 1; i <= 4; i++) {

  MENU.push("menu" + i + =document.getElementsByClassName('menu' + i +));

}
for (let j = 1; j < 5; j++) {
    for (let i = 0; i < MENU[j].length; i++) {
        MENU[j][i].addEventListener('click', function(){ MENU[j][i].classList.add("test"); });
    }
}

预期结果:

与“工作代码”相同的结果:

当我点击“menu1”div 时:


<div class ="menu1 item1-1 test"></div>
<div class ="menu1 item1-2 test"></div>
<div class ="menu1 item1-3 test"></div>
<div class ="menu1 item1-4 test"></div>

<div class ="menu2 item2-1"></div>
<div class ="menu2 item2-2"></div>
<div class ="menu2 item2-3"></div>
<div class ="menu2 item2-4"></div>

<div class ="menu3 item3-1"></div>
<div class ="menu3 item3-2"></div>
<div class ="menu3 item3-3"></div>
<div class ="menu3 item3-4"></div>

<div class ="menu4 item4-1"></div>
<div class ="menu4 item4-2"></div>
<div class ="menu4 item4-3"></div>
<div class ="menu4 item4-4"></div>

实际错误信息: “意外令牌=” “未捕获的 TypeError:MENU[0][i].addEventListener 不是函数”

编辑:我发现了巨大的语法错误,已修复,但我现在收到此错误。

Edit2:我的问题过于开放且不具体,我缩小范围并更正了 cmets 建议的一些语法。

Edit3:我正在尝试:

单击“menu1”元素以选择所有“menu1”元素。 单击“menu2”元素以选择所有“menu2”元素。 单击“menu3”元素以选择所有“menu3”元素。 单击“menu4”元素以选择所有“menu4”元素。

【问题讨论】:

  • 您展示的代码在第一个 i 之后缺少 + 符号,应该类似于 MENU.push("menu" + i + "=document.getElementsByClassName('menu" + i +"')");
  • 我的另一个考虑是为什么你有这么多classes?而不是调用类menu1, menu2等。你可以有一个类menu,如果需要在你的css样式中每个类,如.menu:first-child, .menu:nth-child(2)等,那么你的代码会更容易只有一次调用var menus = document.getElementsByClassName('menu');和变量@987654333 @你有元素数组

标签: javascript for-loop variables getelementsbyclassname


【解决方案1】:

为每个menupanl等添加一个泛型类,例如:menu。这样您的元素将如下所示:

<div class="menu menu1"></div>
<div class="menu menu2"></div>
<div class="menu menu3"></div>
<div class="menu menu4"></div>

现在您可以使用一个选择器选择所有元素。

var menus = document.getElementsByClassName('menu');
console.log(menus[0]); // <div class="menu menu1"></div>
console.log(menus[1]); // <div class="menu menu2"></div>
console.log(menus[2]); // <div class="menu menu3"></div>
console.log(menus[3]); // <div class="menu menu4"></div>

它们存储在HTMLCollection 中,您可以使用for 循环对其进行循环。

for (var i = 0; i < menus.length; i++) {
    console.log(menus[i]); // Logs each <div class="menu"> element.
}

查看the documentation of MDN 以查看有关如何使用getElementsByClassName 方法的更多示例。

【讨论】:

  • 这个想法不适用,我添加了HTML以便更好地理解问题,抱歉之前没有添加。
  • 所以你想一次选择所有menu元素?
  • @EmielZuurbier 我想在单击“menu1”元素时选择所有“menu1”元素。我再次编辑了帖子,我正在尝试改进我的问题以更好地解释问题。
【解决方案2】:

您可以使用querySelectorAll

类似这样的:

const selector = '';
for (let i = 1; i <= 4; i++) {
  selector += `${selector ? ', ' : ''}menu${i}, panel${i}, navprev${i}, navrtrn${i}, navnext${i}`
}

document.querySelectorAll(selector).forEach(element => {
  element.addEventListener('click', (event) => {
    // check if it is a menu:
    if (event.target.matches('[class^=menu]')) {
       // a menu was clicked
    }
  });
});

如果您不想更改任何其他代码,可以这样做:

const classNamePrefixes = ['menu', 'panel', 'navprev', 'navrtrn', 'navnext'];
const varNameAndClassNamePrefix = classNamePrefixes.map((cnp) => {
  const varName = cnp.replace('nav', '').replace('panel', 'panl');
  return {
    varName,
    cnp
  };
});

for (let i = 1; i <= 4; i++) {
  varNameAndClassNamePrefix.forEach(({ varName, cnp }) => {
     window[`${varName}${i}`] = document.getElementsByClassName(`${cnp}${i}`)
  });
}

【讨论】:

  • 我用 HTML 和更好的范围解决了这个问题,[class^=menu] 不起作用,请再次阅读整个问题,很抱歉一开始没有更具体。
  • @ArtRS 我的第二个示例将生成您最初拥有的变量,因此您无需更改任何其他内容(它将创建menu1menu2menu3 等. 变量)。将属性添加到window(例如:window.menu1 = ....)并创建一个全局变量(您可以像menu1.addEventListener.... 一样访问它)。
【解决方案3】:

你为什么不给他们另一个特殊的属性就像&lt;div class="whatever" specialAttribute&gt;Some Html content&lt;/div&gt;一样?然后像const selectors=document.querySelectorAll("[specialAttribute]");一样使用选择器

【讨论】:

  • 我已经在使用一个特殊属性。我用 HTML 和更好的范围解决了这个问题,请再次阅读整个问题,很抱歉一开始没有更具体。
【解决方案4】:

如果您将项目分配到索引中的序数位置,则会容易得多。

  MENU[i] = document.getElementsByClassName('menu" + i);

然后 MENU[1] 将是对第一个元素的引用,等等。

【讨论】:

  • 我用 HTML 和更好的范围解决了这个问题,MENU[i] 不起作用,请再次阅读整个问题,很抱歉一开始没有更具体。
【解决方案5】:

你不应该推送字符串,只是推送调用函数的结果。

MENU.push(document.getElementsByClassName('menu' + i));

请注意,数组索引从 0 开始。所以MENU[0] 将包含类menu1 的元素,以此类推。

【讨论】:

  • 你应该提到循环从0开始,类名从1开始。
  • 我用 HTML 和更好的范围解决了这个问题,MENU[0] 不起作用,请再次阅读整个问题,很抱歉一开始没有更具体。
猜你喜欢
  • 1970-01-01
  • 2011-08-22
  • 2019-05-28
  • 1970-01-01
  • 2020-08-06
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多