使用 Javascript 循环创建多个 HTML 元素

Posted

技术标签:

【中文标题】使用 Javascript 循环创建多个 HTML 元素【英文标题】:Using Javascript loop to create multiple HTML elements 【发布时间】:2018-03-26 02:05:06 【问题描述】:

我想使用 javascript 循环来创建多个 html 包装器元素并将 JSON 响应 API 数据插入到某些元素(图像、标题、url 等)中。

这是我需要逐行处理的东西吗?

<a class="scoreboard-video-outer-link" href="">
  <div class="scoreboard-video--wrapper">
    <div class="scoreboard-video--thumbnail">
      <img src="http://via.placeholder.com/350x150">
    </div>
    <div class="scoreboard-video--info">
      <div class="scoreboard-video--title">Pelicans @ Bulls Postgame: E'Twaun Moore 10-8-17</div>
    </div>
  </div>
</a>

我正在尝试什么:

var link = document.createElement('a');
document.getElementsByTagName("a")[0].setAttribute("class", "scoreboard-video-outer-link");
document.getElementsByTagName("a")[0].setAttribute("url", "google.com"); 
mainWrapper.appendChild(link);

var videoWrapper= document.createElement('div');
document.getElementsByTagName("div")[0].setAttribute("class", "scoreboard-video-outer-link");
link.appendChild(videoWrapper);

var videoThumbnailWrapper = document.createElement('div');
document.getElementsByTagName("div")[0].setAttribute("class", "scoreboard-video--thumbnail");
 videoWrapper.appendChild(videoThumbnailWrapper);

var videoImage = document.createElement('img');
document.getElementsByTagName("img")[0].setAttribute("src", "url-of-image-from-api");
videoThumbnailWrapper.appendChild(videoImage);

然后我基本上对所有嵌套的 HTML 元素重复该过程。

创建 A 标记 为 A-tag 创建 class 和 href 属性 将类名和 url 附加到属性

将 A 标记附加到主包装器

创建 DIV

为 DIV 创建类属性 将 DIV 附加到新附加的 A 标记

如果您能就我在此解释的最佳方式向我提供指导,我将不胜感激?好像会很乱。

【问题讨论】:

到目前为止您尝试了哪些方法,您在上面的哪一部分遇到了问题? 我正在做我上面描述的事情。例如: var link = document.createElement('a'); document.getElementsByTagName("a")[0].setAttribute("class", "scoreboard-video-outer-link"); document.getElementsByTagName("a")[0].setAttribute("url", "google.com"); mainWrapper.appendChild(link); 然后我基本上对所有嵌套的 HTML 元素重复这个过程。 这样的模板化 HTML 是一个很常见的问题。如此常见,其实有很多 JavaScript 框架都可以做到。我建议你研究像 React、Vue 或 Angular 这样的框架。 谢谢西德尼。我会更多地研究这些框架。我以前使用 VUE 创建站点,但从未创建过这样的循环。这最终会出现在 Drupal 页面上,所以我也必须更仔细地探索这段婚姻。 @4ndy 请编辑/更新您的问题并包括您尝试过的内容。谢谢。 【参考方案1】:

这是我的答案。已注明。为了查看 sn-p 中的效果,您必须进入开发人员控制台以检查包装器元素或查看开发人员控制台日志。

我们基本上创建了一些辅助方法来轻松地创建元素并将它们附加到 DOM - 这真的没有看起来那么难。这也应该让您可以轻松地将 JSON 检索到的对象作为属性附加到您的元素!

这是一个基本版本,可让您了解正在发生的事情以及如何使用它

//create element function

function create(tagName, props) 
  return Object.assign(document.createElement(tagName), (props || ));


//append child function

function ac(p, c) 
  if (c) p.appendChild(c);
  return p;


//example: 
//get wrapper div
let mainWrapper = document.getElementById("mainWrapper");

//create link and div
let link = create("a",  href:"google.com" );
let div = create("div",  id: "myDiv" );

//add link as a child to div, add the result to mainWrapper
ac(mainWrapper, ac(div, link));

//create element function

function create(tagName, props) 
  return Object.assign(document.createElement(tagName), (props || ));


//append child function

function ac(p, c) 
  if (c) p.appendChild(c);
  return p;


//example: 
//get wrapper div
let mainWrapper = document.getElementById("mainWrapper");

//create link and div
let link = create("a",  href:"google.com", textContent: "this text is a Link in the div" );
let div = create("div",  id: "myDiv", textContent: "this text is in the div! " );

//add link as a child to div, add the result to mainWrapper
ac(mainWrapper, ac(div, link));
div 
border: 3px solid black;
padding: 5px;

&lt;div id="mainWrapper"&gt;&lt;/div&gt;

以下是如何使用更完整的注释代码来具体执行您所要求的操作。

//get main wrapper
let mainWrapper = document.getElementById("mainWrapper");

//make a function to easily create elements
//function takes a tagName and an optional object for property values
//using Object.assign we can make tailored elements quickly.

function create(tagName, props) 
  return Object.assign(document.createElement(tagName), (props || ));



//document.appendChild is great except 
//it doesn't offer easy stackability
//The reason for this is that it always returns the appended child element
//we create a function that appends from Parent to Child 
//and returns the compiled element(The Parent).
//Since we are ALWAYS returning the parent(regardles of if the child is specified) 
//we can recursively call this function to great effect
//(you'll see this further down)
function ac(p, c) 
  if (c) p.appendChild(c);
  return p;


//these are the elements you wanted to append
//notice how easy it is to make them!

//FYI when adding classes directly to an HTMLElement
//the property to assign a value to is className  -- NOT class
//this is a common mistake, so no big deal!

var link = create("a", 
  className: "scoreboard-video-outer-link",
  url: "google.com"
);

var videoWrapper = create("div", 
  className: "scoreboard-video-outer-link"
);

var videoThumbnailWrapper = create("div", 
  className: "scoreboard-video--thumbnail"
);

var videoImage = create("img", 
  src: "url-of-image-from-api"
);

//here's where the recursion comes in:
ac(mainWrapper, ac(link, ac(videoWrapper, ac(videoThumbnailWrapper, videoImage))));

//keep in mind that it might be easiest to read the ac functions backwards
//the logic is this:

//Append videoImage to videoThumbnailWrapper
//Append (videoImage+videoThumbnailWrapper) to videoWrapper 
//Append (videoWrapper+videoImage+videoThumbnailWrapper) to link
//Append (link+videoWrapper+videoImage+videoThumbnailWrapper) to mainWrapper

let mainWrapper = document.getElementById('mainWrapper');

function create(tagName, props) 
  return Object.assign(document.createElement(tagName), (props || ));


function ac(p, c) 
  if (c) p.appendChild(c);
  return p;


var link = create("a", 
  className: "scoreboard-video-outer-link",
  url: "google.com"
);

var videoWrapper = create("div", 
  className: "scoreboard-video-outer-link"
);

var videoThumbnailWrapper = create("div", 
  className: "scoreboard-video--thumbnail"
);



var videoImage = create("img", 
  src: "url-of-image-from-api"
);

ac(mainWrapper, ac(link, ac(videoWrapper, ac(videoThumbnailWrapper, videoImage))));
//pretty fancy.
//This is just to show the output in the log,
//feel free to just open up the developer console and look at the mainWrapper element.

console.dir(mainWrapper);
&lt;div id="mainWrapper"&gt;&lt;/div&gt;

【讨论】:

谢谢。这很棒。老实说,我还没有尝试过,但它令人大开眼界,并且看起来完全符合发布的代码试图做的事情;这是收拾烂摊子。【参考方案2】:

短版

Markup.js's loops.

加长版

你会发现许多工作解决这个问题的解决方案。但这可能不是重点。重点是:对吗?而且你可能使用了错误的工具来解决这个问题。

我曾使用过类似的代码。我没有写它,但我必须使用它。你会发现这样的代码很快就会变得非常难以管理。你可能会想:“哦,但我知道它应该做什么。一旦完成,我不会改变它。”

代码分为两类:

您停止使用的代码因此无需更改。 您一直使用的代码,因此您需要更改。

那么,“它有效吗?”不是正确的问题。有很多问题,但其中一些是:“我能保持这个吗?它是否容易阅读?如果我改变一个部分,它是只改变我需要改变的部分,还是它也改变了我需要改变的其他部分?不是要改变吗?”

我在这里得到的是您应该使用模板库。 JavaScript 有很多。

一般来说,您应该使用完整的 JavaScript 应用程序框架。现在主要有以下三种:

ReactJS Vue.js 角度 2

为了诚实,请注意我没有遵循自己的建议,仍然使用 Angular。 (原始版本,不是 Angular 2。)但这是一个陡峭的学习曲线。有很多库也包含模板功能。

但是您显然已经建立了一个完整的项目,并且您只想将一个模板插入到 现有 JavaScript 代码中。您可能需要一种模板语言,它可以做它的事情并且不碍事。当我开始的时候,我也想要那个。我使用了 Markup.js 。它很小,很简单,它可以满足你在这篇文章中想要的。

https://github.com/adammark/Markup.js/

这是第一步。我认为它的loops feature 是您所需要的。以此为起点,按时完成一个完整的框架。

【讨论】:

很好的答案。谢谢你。我意识到我可能应该使用 JS 框架来使其可维护。你完美地描述了我的问题。【参考方案3】:

看看这个 - [下划线._template] 它非常小,在这种情况下很有用。 (https://www.npmjs.com/package/underscore.template)。

const targetElement = document.querySelector('#target')

// Define your template
const template = UnderscoreTemplate(
'<a class="<%- link.className %>" href="<%- link.url %>">\
  <div class="<%- wrapper.className %>">\
    <div class="<%- thumbnail.className %>">\
      <img src="<%- thumbnail.image %>">\
    </div>\
    <div class="<%- info.className %>">\
      <div class="<%- info.title.className %>"><%- info.title.text %></div>\
    </div>\
  </div>\
</a>');
 
// Define values for template
const obj = 
  link: 
    className: 'scoreboard-video-outer-link',
    url: '#someurl'
  ,
  wrapper: 
    className: 'scoreboard-video--wrapper'
  ,
  thumbnail: 
    className: 'scoreboard-video--thumbnail',
    image: 'http://via.placeholder.com/350x150'
  ,
  info: 
    className: 'scoreboard-video--info',
    title: 
      className: 'scoreboard-video--title',
      text: 'Pelicans @ Bulls Postgame: E`Twaun Moore 10-8-17'
    
  
;

// Build template, and set innerHTML to output element.
targetElement.innerHTML = template(obj)

// And of course you can go into forEach loop here like

const arr = [obj, obj, obj]; // Create array from our object
arr.forEach(item => targetElement.innerHTML += template(item))
<script src="https://unpkg.com/underscore.template@0.1.7/dist/underscore.template.js"></script>
<div id="target">qq</div>

【讨论】:

以上是关于使用 Javascript 循环创建多个 HTML 元素的主要内容,如果未能解决你的问题,请参考以下文章

使用循环将 javascript 数组值注入多个 HTML 位置

如何使用 for 循环将一段重复的 javascript 打印到 HTML 文档?

html 简单的Javascript循环遍历多个网页。这可以在电视上显示。

使用任何PHP循环从数据库表创建多个html表

使用JS动态创建国家下拉列表[重复]

使用循环创建多个表的 Tabledit