DRY:有条件地应用课程的方式吗?

时间:2018-03-27 10:57:59

标签: javascript ecmascript-6

我正在通过一个数组来根据外部设置的状态应用不同的类。这就是我现在的表现,但我觉得自己很重复自己。有干燥的方法吗?如果有帮助的话,类名可能是其他的东西。

var children2 = Array.from(wrapper.children);
var s = state.state;
children2.forEach((child, i) => {
    var classes = [];
    child.classList.remove('active', 'before', 'previous', 'next', 'after');
    if(i < s) { classes.push('before'); };
    if(i > s) { classes.push('after');  };
    if(i === s) { classes.push('active') }
    if(i === s - 1) { classes.push('previous') }
    if (i === s + 1) { classes.push('next') }
    child.classList.add(...classes)
})

3 个答案:

答案 0 :(得分:6)

最简单的解决方案是使用toggle

  

toggle( String [, force] )

     

当只存在一个参数时:切换类值;即,如果类存在则删除它并返回false,如果不存在,则添加它   返回true。

     

当存在第二个参数时:如果第二个参数的计算结果为true,则添加指定的类值,如果它的计算结果为   是的,删除它。

例如:

let classes = child.classList;
classes.toggle('before', i < s);
classes.toggle('after', i > s);
classes.toggle('active', i === s);
classes.toggle('previous', i === s-1);
classes.toggle('next', i === s+1);

您还可以创建一个包含键和条件的对象,然后将它循环到toggle个别区域:

const classes = {
  before: i < s,
  after: i > s,
  active: i === s,
  previous: i === s - 1,
  next: i === s + 1,
};
Object.entries(classes).forEach(([className, condition]) => child.classList.toggle(className, condition));

(请注意Object.entries是一项ECMAScript 2017功能。)

答案 1 :(得分:0)

这是一种方式:

var children2 = Array.from(wrapper.children);
var s = state.state;

//Represent your states as StateName-Predicate map
const States = {
  'active': (i,s) => i===s,
  'before': (i,s) => i<s},
  'previous': (i,s) => i===s-1,
  'next': (i,s) => i===s+1,
  'after': (i,s) => i>s
};


children2.forEach((child, i) => {    
    const classList = child.classList;
    
    //Iterate over all available states
    Object.keys(States).forEach(stateName => {
      //Extract predicate function for a state
      const predicate = States[stateName];
      //If predicate evaluates to true - set class, otherwise - remove it
      classList.toggle(stateName, predicate(i,s) );  
    });
    
})

答案 2 :(得分:0)

目前在您的代码中有一种模式非常重复:&#34; if(某些条件),添加此类&#34;。你可能会做这样的事情:

var classes = [
  i < s && 'before',
  i > s && 'after',
  i === s && 'active',
  i === s - 1 && 'previous',
  i === s + 1 && 'next'
].filter(x => x)

该代码的第一部分var classes = [...]通过有条件地添加项目来创建类似[false, false, 'active', false, false]的数组。例如,假设i为3而s也为3.当JavaScript评估i === s && 'active'时,它会看到i (3) === s (3),因此它会转到下一个值,即'active',并将其粘贴在数组中。在评估i === s + 1 && 'next'时,它会发现i (3) s + 1 (4)相同,因此它会立即显示为false并将其添加到列表中。

然后,我们使用filter来删除那些false项,因此我们得到一个更像['active']的数组。基本上,filter接受一个函数并将数组项中的每一个逐个传递给它;当函数返回truthy值时,它会保留项目,否则会删除该项目。我们传递的函数是arrow function;它只返回传递给它的值。您可以将其替换为function(x) { return x },它在功能上也是相同的。

(我有时会使用.filter(Boolean)代替.filter(x => x)Boolean可以用作将值转换为布尔值的函数(根据上面的"truthy"链接) - 如果您以前见过!!x syntax,它会做同样的事情。我发现.filter(Boolean)更多语法:&#34;保持真实的项目(如布尔值)&#34;。但这完全没有必要,因为filter本身会自动检查你的函数的返回值是否真实。所以如果你使用它只是一个品味问题!)

另一种选择是摆脱不必要的括号和分号,如下所示:

if (i < s) classes.push('before')
if (i > s) classes.push('after')
// ..and so on.

它肯定有点冗长,但无论如何你可能更喜欢它!