【问题标题】:JS / Coffee + HTML, simpler way to set conditional classJS / Coffee + HTML,设置条件类的更简单方法
【发布时间】:2014-02-08 07:14:30
【问题描述】:

所以,当我从 javascript(或 coffeescript,我根据具体情况使用两者)渲染 html 模板时,我发现我有一个非常常见的情况,看起来不必要地笨重。例如:

我有一个这样的 JS 对象:

var thingy = {
  name: 'Some Thing',
  category: 'widget',
  active: true
};

我可能想像这样将它渲染成 html:

<div class="widget active">Some Thing</div>

总觉得笨拙的一点是将 javascript 中的布尔检查转换为 css 类字符串。我通常最终做的是这样的:

function renderThing(thing) {
  var klass = thing.active ? thing.category + " active" : thing.category
  return '<div class="'+klass+'">'+thing.name+'</div>';
}

在coffeescript中这感觉更长,因为三元更冗长:

renderThing = (thing) ->
  klass = if thing.active then thing.category + " active" else thing.category
  '<div class="'+klass+'">'+thing.name+'</div>'

当只有一个这样的属性时,这并不算太糟糕,但如果你最终遇到三个或四个这样的情况,代码很快就会变得非常冗长。

所以,我想知道,是否有人对更简洁和/或更易读的方式有想法/建议?

【问题讨论】:

  • klass = thing.category; if (thing.active) klass += " active"?
  • 您能否更具体地说明“四分之三的情况”,也许是一个示例代码?你的意思是四个三元运算符?可以循环吗?
  • @Bergi 是的,我的意思是使用多个三元运算符,例如,如果一个对象可以具有多个类型的状态,例如 selectedcurrentactivedisabled 或 @987654330 @ 等。我尽量不给出一个过于具体的例子,因为我更多地认为这是一个我发现在 javascript 编程中经常遇到的一般问题。

标签: javascript html coffeescript


【解决方案1】:

如果我做了很多这样的事情,那么我会编写一个简单的函数,或多或少地提供我自己的“将布尔值转换为字符串”:

if_true = (f, s) ->
    return s if(f)
    return ''

然后进行一点字符串插值来构建类字符串:

klass = "#{if_true(o.active, 'active')} #{o.category}"

如果您不喜欢 !o.active 时的杂散空间,那么您可以将该空间移到 if_true 参数中:

klass = "#{if_true(o.active, 'active ')}#{o.category}"

如果你有一大堆标志,把它们的名字扔进一个数组,然后使用循环推导来构建一个类名数组:

o =
    first: true
    second: true
    third: false
    fourth: undefined
    fifth: 'element'
    category: 'pancakes'

flags = [ 'first', 'second', 'third', 'fourth', 'fifth' ]

klasses = (if_true(o[f], f) for f in flags)
klasses.push(o.category)
klass = klasses.join(' ')

演示:http://jsfiddle.net/ambiguous/eGDaa/

【讨论】:

    【解决方案2】:

    当只有一个这样的属性时,这并不算太糟糕,但如果你 最终出现三四个代码很快变得非常 详细。

    确实会。看起来是从 switch 使用 assign 的理想场所——也就是说,如果只有一个“附加”类:

    score = 76
    grade = switch
      when score < 60 then 'F'
      when score < 70 then 'D'
      when score < 80 then 'C'
      when score < 90 then 'B'
      else 'A'
    

    但这将是 1 个输入等于 1 个输出,这可能不是您想要的。也许你需要:

    renderThing = (thing) ->
      cssClass = thing.category
      keysToCss = ["active", "disabled", "delta", "gamma", "epsilon"]
    
      for k,v of thing 
       if lodash.contains(keysToCss, k) # I'm using lodash here, same as Underscore
         cssClass += " #{k}" 
    
      "<div class='#{cssClass}'></div>"
    

    另外,我认为一旦你开始像这样混合标记和代码,你就需要开始研究像 Angular 这样的工具。

    【讨论】:

    • 其实我一般不会混合标记和代码,但几乎总是使用javascript模板将标记排除在代码之外。问题在于,在模板本身中,我经常遇到一种情况,我想将模型的某些属性转换为类名模式。通常我会编写一个函数或类似model.className() 之类的东西来执行逻辑,但即便如此,考虑到这是一个概念上如此简单的事情,逻辑最终还是会感觉非常复杂。
    【解决方案3】:

    检查coffeescripts loop comprehensions 以迭代一堆标志并构建一个可以连接到类值的列表:

    renderThing = (thing) ->
      flags = ["selected", "current", "active", "disabled", "bookmarked"];
      klasses = (f for f in flags when thing[f])
      klasses.push thing.category
      "<div class=\"#{klasses.join(" ")}\">#{thing.name}</div>"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-10
      • 2011-05-25
      • 2018-12-01
      • 2015-06-09
      • 1970-01-01
      • 2019-11-29
      • 2023-03-31
      • 1970-01-01
      相关资源
      最近更新 更多