是否可以在JavaScript中自动声明数千个变量?

时间:2019-02-10 18:55:23

标签: javascript html css json

我对JavaScript还是比较陌生,所以我不确定我是否在这里按常规方式做事,不确定是否有更好的方法来做我想做的事。

我有一个JavaScript函数,该函数从JSON文档中提取大约3600个句子并将其自动插入到我的HTML代码中。在HTML中,每个ID都会生成一次唯一的ID。

我想为每个句子创建一个onclick事件,以便在单击该句子时在该句子的下方显示更多信息。这意味着我必须声明数千个变量,每个句子一个,与该句子关联的每个信息div一个:

var sent1 = document.getElementById('s1');
var sent1info = document.getElementById('s1info');
var sent2 = document.getElementById('s2');
var sent2info = document.getElementById('s2info');
var sent3 = document.getElementById('s3');
var sent3info = document.getElementById('s3info');
...

这是太多手动操作。有没有一种方法可以自动声明这些变量,或者有更好的方法来完成我正在做的事情?

对于上下文,我对每个变量的意图是将其馈入此函数:

sent1.onclick = function(){
    if(sent1info.className == 'open'){
        sent1info.className = 'close';
    } else{
        sent1info.className = 'close';
    }
};

当className为'close'时,CSS将从此处将信息框降低为0,而当className为'open'时将其展开。但是,再次,这将要求我将此功能编写数千次。

有没有办法自动执行此操作?还是我要解决所有这些错误?

编辑以显示HTML:

<!DOCTYPE html>
<html>
<head>...</head>
<body>
    <div id="everything">
        <header id="theheader" class="clearfix">...</header>
        <div id="thebody" class="box clearfix">
            <aside id="page" class="side">...</aside>
            <div class="items">
                <article id="content" class="article">
                    <img id="sentpic" src="sentpic.jpg">
                    <h1>Sentences</h1>
                    <div id="sentences">
                        *** This is where the JS inserts sentences and information ***
                        <ul id='sent1' class='sentcontent'><li class='number'>1.</li><li class='thesent'>...</li></ul>
                        <div id='sent1info' class='infobox'>
                            <ul class='sentinfo'><li class='information'>Info:</li><li class='infotext'><em>...</em></li></ul>
                            <ul class='sentinfo'><li class='information'>Line:</li><li class='line'>...</li></ul>
                        </div>
                        <ul id='sent2' class='sentcontent'><li class='number'>2.</li><li class='thesent'>...</li></ul>"
                        <div id='sent2info' class='infobox'>
                            <ul class='sentinfo'><li class='information'>Info:</li><li class='infotext'><em>...</em></li></ul>
                            <ul class='sentinfo'><li class='information'>Line:</li><li class='line'>...</li></ul>
                        </div>
                        *** it goes on like this for each sent inserted ***
                    </div>
                </article>
            </div>
        </div>
        <div class="associates clearfix">...</div>
        <footer class="foot">...</footer>
    </div>
    <script type="text/javascript" src="index.js"></script>
</body>
</html>

3 个答案:

答案 0 :(得分:2)

使用HTML <details>元素:

const json = [
  {thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
  {thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];

const template_sentence = (ob, i) => `
<details class="sentence">
  <summary>${i+1} ${ob.thesent}</summary>
  <h3>${ob.info}</h3>
  <div>${ob.line}</div>
</details>`;

document.querySelector("#sentences").innerHTML = json.map(template_sentence).join('');
<div id="sentences"></div>


否则,通过使用当前的非语义标记:

不需要按ID定位(在您的具体情况下)。还有其他方法,例如CSS中的+ Next Adjacent兄弟姐妹选择器。

这是一个JS示例-应该不言自明,但是可以随便问。

  • 使用JS将类(在此示例中为.active)切换到可点击的UL元素
  • 使用CSS和下一个相邻的同级选择器+来创建 info DIV display: block

/* Just a sample... you'll know how to modify this with the right properties I hope */
const json = [
  {thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
  {thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];

// The toggle function:
const toggleInfobox = ev => ev.currentTarget.classList.toggle("active");

// A single sentcontent template
const template_sentence = (ob, i) =>
`<ul class='sentcontent'>
    <li class='number'>${i+1}</li>
    <li class='thesent'>${ob.thesent}</li>
  </ul>
  <div class='infobox'>
    <ul class='sentinfo'>
      <li class='information'>Info:</li>
      <li class='infotext'><em>${ob.info}</em></li>
    </ul>
    <ul class='sentinfo'>
      <li class='information'>Line:</li>
      <li class='line'>${ob.line}</li>
    </ul>
</div>`;

// Get target element
const el_sentences = document.querySelector("#sentences");

// Loop JSON data and create HTML
el_sentences.innerHTML = json.map(template_sentence).join('');

// Assign listeners
const el_sentcontent = el_sentences.querySelectorAll(".sentcontent");
el_sentcontent.forEach(el => el.addEventListener('click', toggleInfobox));
/* BTW, why do you use <ul> ? That's not a semantic list! */
.sentcontent { padding: 0; cursor: pointer;}
.sentcontent li { display: inline-block; }

/* Arrows are cool, right? */
.sentcontent:before        { content: "\25BC"; }
.sentcontent.active:before { content: "\25B2"; }

/* Hide adjacent .infobox initially, 
/* and show adjacent .infobox on JS click */
.sentcontent        + .infobox { display: none; }
.sentcontent.active + .infobox { display: block; }
<div id="sentences"></div>

在此Stack overflow answer中,您可以找到有关在某些按钮单击上切换元素的更多信息。

答案 1 :(得分:1)

这个问题更多的是架构问题,而不是创建动态变量的需要。考虑以下示例:

  • id被删除(使用现有的类名)
  • 此模式可扩展n个句子实例
  • handleClick中,我们在clicked元素上切换open类,这使我们可以通过CSS利用相邻的兄弟选择器
  • 不需要close类,因为缺少open类表示关闭状态。

let outerUL = document.querySelectorAll('.sentcontent')

function handleClick() {
  this.classList.toggle('open');
}

outerUL.forEach(ul => {
  ul.addEventListener('click', handleClick);
})
.sentcontent {
  cursor: pointer;
}

.sentcontent.open + .infobox {
   display: block;
}

.infobox {
  background-color: #eee;
  display: none;
  padding: .25em .5em;
}
<ul class='sentcontent'>
  <li class='number'>1.</li>
  <li class='thesent'>Sent</li>
</ul>
<div class='infobox'>
  <ul class='sentinfo'>
    <li class='information'>Info</li>
    <li class='infotext'><em>Info text</em></li>
  </ul>
  <ul class='sentinfo'>
    <li class='information'>Line info</li>
    <li class='line'>Line</li>
  </ul>
</div>

<ul class='sentcontent'>
  <li class='number'>2.</li>
  <li class='thesent'>Sent</li>
</ul>
<div class='infobox'>
  <ul class='sentinfo'>
    <li class='information'>Info</li>
    <li class='infotext'><em>Info text</em></li>
  </ul>
  <ul class='sentinfo'>
    <li class='information'>Line info</li>
    <li class='line'>Line</li>
  </ul>
</div>

https://jsfiddle.net/d91va7tq/2/

答案 2 :(得分:1)

当您有非常大的json数据时,要牢记不要立刻渲染整个数据,这将影响Web浏览器的性能。而是在需要时渲染。这就是用户单击以获取更多信息的时候。

我在下面做了一些例子,请确保也阅读评论

const json = [
  {thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
  {thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];

const container = document.querySelector(".container");
json.forEach((item)=> {
let x= item;
let el = document.createElement("li");
el.innerHTML = x.thesent;
container.appendChild(el);
el.addEventListener("click",()=> {
var infoContainer= el.querySelector(".info");
// dont create all html element at once, instead create them 
//when the user click on it. this is better when you have a very large data.
if (!infoContainer){ // not created, then create  
    infoContainer = document.createElement("div");
    infoContainer.className="info";
    var info = document.createElement("div");
    var line = document.createElement("div");
    info.innerHTML = x.info;
    line.innerHTML = x.line;
    infoContainer.appendChild(info);
    infoContainer.appendChild(line);
    el.appendChild(infoContainer);
} else if (infoContainer.style.display == "none") // created and hidden, then display it 
           infoContainer.style.display = "block";
  else infoContainer.style.display= "none"; // already displayed then hide it 
});
})
.container li >div.info >div:first-child{
font-size: 12px;

}

.container li >div.info >div:last-child{
font-size: 10px;

}
<ul class="container">

</ul>