javascript逻辑在html模板上追加/前置div

时间:2017-08-25 00:53:34

标签: javascript jquery html css

我写了一个非常基本的网络应用程序,它从API中提取食谱数据。通过推送到javascript文件中定义的html模板来呈现数据。布局通过CSS中的浮动网格进行控制。

呈现结果并推送到模板的代码部分:

function displayRecipeSearchData(data) {
  var results = ' ';
  if (data.hits.length) {
    data.hits.forEach(function(item) {
      results += template.item(item);
    });
  }
  else {
    results += '<p> No results </p>';
  }
  $('#js-search-results').html(results);
}

显示响应的html模板:

const template = {
  item: function(item) {
    return '<div class ="col-4">' +
             '<div class ="result">' +
               '<div class="recipelabel">' +
                 '<div class="reclist">' + item.recipe.ingredientLines + '</div><!-- end reclist -->' +
                  '<p class="label">' + item.recipe.label + '</p>' +
                  '<div class="thumbnail">' + 
                    '<a href="'+ httpsTransform(item.recipe.url) + '" target="_blank">' +
                      '<img src="' + item.recipe.image + '"alt="' + item.recipe.label + '">' +
                    '</a>' +
                    '<div class="recipesource">' +
                      '<p class="source">' + item.recipe.source + '</p>' +
                    '</div><!-- end recipesource -->' +
                  '</div><!-- end thumbnail -->' +
                '</div><!-- end recipelabel -->' +
              '</div><!-- end result -->' + 
            '</div><!-- end col-4 -->';
  }
};

我正在尝试更改displayRecipeSearchData函数中的逻辑,这样,对于每组三个结果,<div></div>围绕三个结果的块。这样行/列始终在flex网格中工作。我已经尝试了几种方法,但还没有得到正确的语法/逻辑。嵌套在现有语句中的if语句是否有效?

if(i % 3 === 0 ){ results. += '<div class="row">''</div>'}

任何建议都将不胜感激。

2 个答案:

答案 0 :(得分:1)

您可以使用另一个变量来存储一行HTML:

function displayRecipeSearchData(data) {
  var results = ' ', row = '';
  if (data.hits.length) {
    data.hits.forEach(function(item, i) {
      row += template.item(item);
      if (i % 3 == 2) { // wrap row and add to result
        results += '<div class="row">' + row + '</div>';
        row = '';
      }
    });
    if (row.length) { // flush remainder into a row
      results += '<div class="row">' + row + '</div>';
    }
  }
  else {
    results += '<p> No results </p>';
  }
  $('#js-search-results').html(results);
}

答案 1 :(得分:0)

在我看来,你肯定是这么做的。

而不是手动将模板写为字符串并尝试将字符串注入正确的位置(可能创建无效的html),您应该使用javascripts内置元素创建。在自己的职能中创造孩子也会更加模块化。使用函数而不是对象来保存对象创建者也会容易得多。我的版本可能有更多代码,但从长远来看,修改起来会容易得多

const Itemizer = function(){
  this.items = [];
  const createEl = function(elType, classes, attributes, text, html){
    let el = document.createElement(elType)
    for(let i = 0; i < classes.length; i++){
      el.classList.add(classes[i]
    }
    for(let attr in attributes){
      el.setAttribute(attr, attributes[attr])
    }
    if(text){
      el.innerText = text
    }
    if(html){
      el.innerHTML = html
    }
    return el
  };

  const createThumbnail = function(url, image, alt, source){
    let thumbnail = createEl("DIV", ["thumbnail"]),
        link = createEl("A", [], {href: httpsTransform(url)}),
        img = createEl("IMG", [], {src: image, alt: label});
        rSource = createRecipeSource(source)
    link.appendChild(img);
    thumbnail.appendChild(link);
    thumbnail.appendChild(rSource)
    return thumbnail
  };

  const createRecipeSource = function(source){
    let wrapper = createEl("DIV", ["recipe-source"]);
    wrapper.appendChild(createEl("P", ["source"], {}, source))
    return wrapper
  }

  const createRecipeLabel = function({
    recipe: {
      ingredientLines,
      label,
      url,
      source
    }
  }){
    let labelWrapper = createEl("DIV", ["recipe-label"),
        ingredients = createEl("DIV", ["rec-list"], {}, false, ingredientLines),
        recipeLabel = createEl("P", ["label"], {}, label),
        thumbnail = createThumbnail(url, image, label, source)
    labelWrapper.appendChild(ingredients)
    labelWrapper.appendChild(recipeLabel)
    labelWrapper.appendChild(thumbnail)
    return labelWrapper
  }

  const createNewItem = function(data){
    let columnWrapper = createEl("DIV", ["col-4"]),
        result = createEl("DIV", ["result"]),
        label = createRecipeLabel(data)

    columnWrapper.appendChild(result)
    result.appendChild(label)
    this.items.push(columnWrapper)
    return columnWrapper
  }.bind(this)

  const getItems = function(){
   return this.items
  }.bind(this)

  const getRows = function(){
    const rows = []
    let row;
    for(let i = 0; i < this.items.length; i++){
      const item = this.items[i]
      if(i % 3 === 0){
        row = createEl("DIV", ["row"])
        rows.push(row)
      }
      row.appendChild(item)
    }
    return rows;
  }.bind(this)

  return {
    add: createNewItem,
    get: getItems,
    rows: getRows
  }
}

然后您可以使用如下函数:

const template = new Itemizer()
function displayRecipeSearchData(data) {
  let rows
  if (data.hits.length) {
    for(let i = 0; i < data.hits.length; i++){
      template.add(data.hits[i])
    }
    rows = template.rows()
  } else {
    const p = document.createElement("P")
    p.innerText = "No Results")
    rows = [p]
  }
  const resultsWrapper = document.getElementById("js-search-results");
  for(let i = 0; i < rows.length; i++){
    resultsWrapper.appendChild(rows[i])
  }
}

将css类与连字符分开也是一种很好的形式,所以我替换了一些你的类名来反映

同样重要的是要注意,实际上您不需要超过1行。如果您将所有项目包装在一个row部分中,当列数达到网格限制时,列会自动溢出到下一行

我的最后一点是永远不会使用目标空白。它违背了正确的用户体验,并在您的应用程序中创建安全漏洞。如果您的用户需要在新标签页中打开,则可以按住ctrl或点击“在新标签页中打开”