【问题标题】:Using Switch Statement to style/color multiple elements, through use of setAttribute() (Javascript)使用 Switch 语句为多个元素设置样式/颜色,通过使用 setAttribute() (Javascript)
【发布时间】:2017-10-15 12:07:29
【问题描述】:

我正在构建一个网页,用于检测您所在地区的天气预报。然而,为了让它独一无二,我试图让网页在界面上改变它的颜色。它会根据天气 api 中的天气图标来改变颜色。 (即 weath.weather[0]["icon"] )。我试图让它尽可能快地运行,同时让它更容易理解。所以我正在寻找一种替代方法。

我决定将颜色更改函数存储在一个变量中,以便它可以重复使用多次,这样我就可以缩短 Switch 语句。它包含一个可以重用的 CSS 字符串变量。该字符串是 setAttribute 函数的样式属性:

var coloring = function(id, Text, Background) {
    var colorChange = "color: " + Text + "; background: " + Background + ";";
    document.getElementById(id).setAttribute("style", colorChange);
};

这将用于通过引用它们的 id 来更改 Dom 的各种元素/部分的颜色。这是 Dom:

<body id="background">  
  <div id="header">
<h1>Local Weather Detector</h1>
  </div>
  <div id="location">
  <h5 id="locIntro">Today's weather from Location...</h5>
  </div>
  <div id="box">
  <div id="temperature">
    <p><strong>Today, </strong>The temperature in your area is...
    <button id="tempSwap">
      </button></p>
  </div>
  
  <div id="weather">
    <p>- and the general forecast is...</p>
  </div>
    </div>
   <div id="copywrite"><h6> &#9400; Thomas Jackson</h6>
      <h6>(Project for Free Code Camp, Full Stack course)</h6></div>
</body>

我会从 api 获取图标数据,然后 switch 语句将根据它是哪个图标来确定需要更改哪些颜色。每个使用 coloring() 函数的 Switch Case 都会将 Dom 的颜色更改为自己设置的颜色:

$.getJSON(api, function(weath) {

  switch (weath.weather[0]["icon"]) {

      case "01d": //clear
        coloring("background", "#f1c40f", "#3498db");
        coloring("box", "#2980b9", "#ecf0f1");
        coloring("temp", "#c0392b", "");
        break;
      case "01d":
      case "03d":
      case "04d":
      case "50d": //cloud
        coloring("background", "#3498db", "#ecf0f1");
        coloring("header", "#f1c40f", "");
        coloring("box", "", "#2980b9");
        coloring("temp", "", "#3498db");
        break;
      case "02d": //cloudClear
        coloring("background", "c0392b", "#2980b9");
        coloring("header", "#f1c40f", "");
        coloring("box", "", "#ecf0f1");
        coloring("temp", "", "#2980b9");
        break;
      case "11d": //thunder
        coloring("background", "#c0392b", "#2980b9");
        coloring("header", "#f1c40f", "");
        coloring("box", "", "#f1c40f");
        coloring("temp", "", "#c0392b");
        break;
      case "13d": //snow
        coloring("background", "#ecf0f1", "#2980b9");
        coloring("header", "#34495e", "");
        coloring("box", "", "#a5f2f3");
        coloring("temp", "", "#34495e");
        break;
      case "03n":
      case "04n":
      case "50n": //cloudNight
        coloring("background", "#ecf0f1", "#7f8c8d");
        coloring("header", "#e74c3c", "");
        coloring("box", "#f1c40f", "#34495e");
        coloring("temp", "", "#2c3e50");
        break;
      case "09n":
      case "10n": //rainNight
        coloring("background", "#3498db", "#2c3e50");
        coloring("header", "#f1c40f", "");
        coloring("box", "#2980b9", "#95a5a6");
        coloring("temp", "#3498db", "#2980b9");
        break;
      case "11n": //thunderNight
        coloring("background", "#f1c40f", "#2c3e50");
        coloring("header", "#e74c3c", "");
        coloring("box", "#c0392b", "#f1c40f");
        coloring("temp", "", "#c0392b");
        break;
      case "13n": //snowNight
        coloring("background", "#f1c40f", "#2c3e50");
        coloring("header", "#a5f2f3", "");
        coloring("box", "#34495e", "#a5f2f3");
        coloring("temp", "#2c3e50", "#f1c40f");
        break;}

}

如果我以错误的方式处理这件事,最好知道。我的主要目标是让其他开发人员更高效、更清晰。

【问题讨论】:

  • 由于代码已经可以运行,我认为这个问题更适合代码审查堆栈交换:codereview.stackexchange.com。在那里,人们可能会给你更好的反馈。
  • 谢谢。有什么方法可以在不复制和粘贴的情况下将其转移到 StackExchange 代码审查?
  • 我认为不可能把它移植到那里。
  • 天哪!我不敢相信代码缩进有多复杂!我只想发这个..

标签: javascript css switch-statement weather-api setattribute


【解决方案1】:

您的处理方式实际上与我所说的“正确”方式相差不远(通常不止一种)——还有一些微优化和清晰的空间虽然是增强剂。

首先,如果您想提高其他维护者的可读性,我建议将图标代码存储在命名常量中。 case: "01d" 并没有告诉我图标是什么,但它确实:

var ICON_STORMY = "01d";
switch (weath.weather[0].icon) {
    case ICON_STORMY:
        ...
        break;
    ...
}

其次,你的着色函数被大量使用了,所以我也会把它收紧一点——不是很多,但也许只是这样它可以被调用一次,而不是为每个id 调用一次。

例如,你可以这样写:

function colorAll(elems) {
    elems.forEach(function (elem) {
        var colorChange = "color: " + elem.text + "; background: " + elem.background + ";";
        document.getElementById(elem.id).setAttribute("style", colorChange);
    });
}

...然后像这样使用该函数:

colorAll([{ id: 'background', text: 'blah blah', background: '#666666' }, { ... }]);

...这个想法是,如果您传递完成整个 switch 案例所需的所有信息,则只需调用一次。

【讨论】:

  • 感谢您的反馈。你所说的离“正确”方式不远的事实告诉我,我正在进步。我了解您对使用变量的看法。但是我不是更好地使用对象列表而不是单个变量吗?我之前有一长串以对象列表形式出现的图标选择。我摆脱了它,因为我认为它会运行得更快,我只是在每个开关盒旁边写了引号。正如你所看到的,我已经这样做了。无论如何感谢您的反馈。
  • @TommyJackson 是的!你敢打赌,这绝对是那些“多于一种”的案例之一。在 switch 语句和对象映射之间,无论您为少数几个值选择哪个,您的性能提升都将可以忽略不计。如果你想变得特别聪明(以牺牲一些可读性为代价),你甚至可以通过像 { '01d': { text: '...', etc } } 这样的图标代码来键入对象。
  • 但是在每个 switch case 旁边添加引号不是更好吗?这将使用更少的代码并解释每个是什么。
  • @TommyJackson 这最终取决于您对标记事物的偏好(即对于其他开发人员)。您不会因为分配额外的参考而受到惩罚;缩小、垃圾收集和本机级别优化完全缓解了性能差异。如果您的目标是简单地“使用更少的代码”,那么带有图标代码的字符串就可以了——如果您的目标是提高可读性,那么命名常量就可以实现该目标,而不会产生明显的性能损失。
【解决方案2】:

函数式思考

switch 语句很有用,但它不适合您编写的其他功能代码。它有副作用,改变状态的机会,副作用,主要不能与其他函数组合

在 switch 语句中应该几乎总是有一个默认情况。我假设。如果在 case 中没有找到相关值,则没有注册Case weath.weather[0]["icon"]。让我们看看我们正在处理的 switch case

$.getJSON(api, function(weath) {

switch (weath.weather[0]["icon"]) {

  case "01d": //clear
    coloring("background", "#f1c40f", "#3498db");
    coloring("box", "#2980b9", "#ecf0f1");
    coloring("temp", "#c0392b", "");
    break;
  case "01d":
  case "03d":
  case "04d":
  case "50d": //cloud
    coloring("background", "#3498db", "#ecf0f1");
    coloring("header", "#f1c40f", "");
    coloring("box", "", "#2980b9");
    coloring("temp", "", "#3498db");
    break;
  default:
    console.log(`case is not registered`);
    break;
  }

}

如果我们转换成三进制,代码如下所示。我正在使用 ES6 箭头函数以获得更好的可读性

$.getJSON(api,(weath) => {

    const icon = weath.weather[0].icon;

    // try to convert switch to if/else or ternary

    icon === '01d' ? coloring() : //coloring methods of 01d
    icon === '02d' ? coloring()   //coloring methods of 02d
                   : console.log('no case matched');

});

这个重复的代码可以用如下函数优化

const switchcase = (cases, defaultCase, key) => {

      if (key in cases) {
        return cases[key]
      } else {
        return defaultCase
      }
}

将柯里化技术应用于上述方法,并使用三元代替传统的if else

const switchcase = cases => defaultCase => key =>
    key in cases ? cases[key] : defaultCase

现在可以像下面这样优化代码

$.getJSON(api, switchcase({
    '01d' : coloring1(),
    '02d' : coloring2()
    })(console.log('no case matched'))(weath.weather[0].icon)
);

switchcase 的早期版本有一个问题,因为在传递给 switchcase 函数之前会评估整个对象字面量。这意味着 coloring1()coloring2() 都被评估。这可能非常危险。

如果对象字面量中的值是函数,那么它们只有在有匹配的情况下才能执行。

代码将更改为

$.getJSON(api, switchcase({ 
    '01d':() => { coloring('x');coloring('...');},
    '02d':() => { coloring('y');coloring('...');}
    })(() => console.log('no cases matched'))(weath.weather[0].icon)
);

优化代码

$.getJSON(api, switchcase({
    01d:() => coloringClear(),
    03d:() => coloringCloud(),
    04d:() => coloringCloud(),
    50d:() => coloringCloud(),
    02d:() => coloringCloudClear(),
    11d:() => coloringThunder(),
    13d:() => coloringSnow(),
    03n:() => coloringCloudNight(),
    04n:() => coloringCloudNight(),
    50n:() => coloringCloudNight(),
    09n:() => coloringRainNight(),
    10n:() => coloringRainNight(),
    11n:() => coloringThunderNight(),
    13n:() => coloringSnowNight()
    })('Unknown')(weath.weather[0]["icon"])
);

将对象保存在单独的变量中以获得更好的可维护性。将所有着色方法移动到上面命名的一种方法中。把它们写成单独的函数

希望以上代码能优化性能

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多