Конвертер температуры HTML / JavaScript с округлением

Я хочу улучшить производительность своего кода с помощью передовых методов и более чистого кода.

Моя цель здесь — просто выполнять преобразование при каждом нажатии клавиши.

Но я заметил, что мой код выглядит очень повторяющимся. На ваш взгляд, что мне сделать, чтобы упростить его?

window.oninput = function(event) {
  var campo = event.target.id;

  // DECIMALS
  var i = document.getElementById("decimalTemp").value;
    ºC.value = (ºC.value * 1).toFixed(i);
    ºK.value = (ºK.value * 1).toFixed(i);
    ºF.value = (ºF.value * 1).toFixed(i);
    ºRa.value = (ºRa.value * 1).toFixed(i);
  // TEMPERATURE
  if (campo == "ºC") {
    ºK.value = (ºC.value * 1 + 273.15).toFixed(i);
    ºF.value = (ºC.value * 1.8 + 32).toFixed(i);
    ºRa.value = ((ºC.value * 1 + 273.15) * 1.8).toFixed(i);
  } else if (campo == "ºK") {
    ºC.value = (ºK.value * 1 - 273.15).toFixed(i);
    ºF.value = (ºK.value * 1.8 - 459.889).toFixed(i);
    ºRa.value = (ºK.value * 1.8).toFixed(i);
  } else if (campo == "ºF") {
    ºC.value = ((ºF.value * 1 - 32) / 1.8).toFixed(i);
    ºK.value = ((ºF.value * 1 + 459.67) / 1.8).toFixed(i);
    ºRa.value = (ºF.value * 1 + 459.67).toFixed(i);
  } else if (campo == "ºRa") {
    ºC.value = (ºRa.value / 1.8 - 273.15).toFixed(i);
    ºK.value = (ºRa.value / 1.8).toFixed(i);
    ºF.value = (ºRa.value * 1 - 459.67).toFixed(i);
  }

};
<h3>Temperature <input type="number" min="0" max="12" value="0" id="decimalTemp" name="decimal" placeholder="Decimal"> <small>Decimals<small></h3>

Celsius (ºC) <input id="ºC" type="number" min="-273.15" value="20">
<br> Kelvin (K) <input id="ºK" type="number" min="0" value="293">
<br> Farenheit (ºF) <input id="ºF" type="number" min="-459.67" value="68">
<br> Rankine (ºRa) <input id="ºRa" type="number" min="0" value="528">

Полный код на JSFiddle

3 ответа
3

Будь проще

Ваш код слишком сложен, поскольку вы делаете слишком много преобразований C <=> F, C <=> Ra и Ra <=> F, которых можно избежать.

При выполнении любого типа преобразования единиц выберите базовую единицу, а затем конвертируйте только базовую единицу и другие единицы.

Используя базовую единицу, вы можете выполнять все преобразования только с 6 формулами, а не с 12, которые вы используете в настоящее время.

Общий обзор

HTML

Важно, чтобы содержимое веб-страницы содержало машиночитаемую информацию, которая была однозначной и семантически значимой. Многим людям нужна помощь для взаимодействия с веб-страницами, если машина не может понять контент, эти люди не могут использовать страницу.

Кроме того, боты (например, поисковые системы, используемые для ранжирования страниц) не могут точно оценить содержимое страницы, если не понимают, что содержит страница.

Я не специалист по HTML, так что это только основные моменты. См. Перезапись для получения дополнительной информации

  • Используйте соответствующие элементы

    • Используйте метки для обозначения входов
    • Различные единицы измерения температуры представляют собой список, используйте неупорядоченный список для хранения входных данных и меток.
  • Связанные данные

    Не! использовать id для хранения семантической информации. Это не значит, что вам не следует использовать осмысленные id имена, вам лучше добавить семантическую информацию, используя более подходящие атрибуты и / или элементы.

    Например, вы используете event.target.id чтобы определить, какая единица изменяется. Вместо того, чтобы использовать идентификатор, сохраните тип блока входных элементов как dataset атрибут. Смотри переписать

JavaScript

  • window

    Ваше использование window является избыточным, поскольку window это глобальный this (область видимости).

    window.oninput = function(event) { идентичен oninput = function(event) {

  • Добавить слушателей не устанавливать слушателей

    Вам следует избегать прямого назначения слушателей событий, поскольку они могут быть перезаписаны вами случайно или сторонним контентом. EG реклама.

    Использовать addEventListener поскольку он добавляет слушателей

    НАПРИМЕР oninput = function(event) { /*... code ... */ } должно быть addEventListener("input", function(event) { /*... code ... */ });

    ПРИМЕЧАНИЕ: название события при использовании addEventListener не включает on приставка. "oninput" становится "input"

  • Константы

    Для переменных, которые не изменяются, объявите их константами. например const campo = event.target.id;

  • Отступ

    Следите за своим отступом, четыре строки ниже var i = document.ge... имеют неправильный отступ.

  • Используйте стандартные символы клавиатуры

    Использование º через танец на клавиатуре ЛЕВЫЙ ALT 167 в этом нет необходимости, поскольку он ничего не добавляет к качеству или удобочитаемости кода.

  • Магические числа

    Числа редко имеют смысл сами по себе. В них также легко ошибиться, если их у вас много. Дайте числам имена, определяя их как константы.

    1.8 может означать что угодно … так что удалите догадки с помощью const RANKINE_SCALE = 1.8

Проблема

Входы могут застрять, потому что шаг ввода и минимальные значения не установлены или неверны

Изменение количества десятичных знаков означает, что вы должны изменить значение шага для каждого ввода. EG Decimal 0, шаг 1, Decimal 1, шаг 0,1, 2, шаг 0,01 и т. Д.

Для управления положением ступеньки нельзя установить min атрибут быть значением, которое не делится на шаг. Для всех по Кельвину и Рэнкину минимальное значение проблематично.

Но, используя Кельвин как базовую единицу, нам нужно только определить его min атрибут и в JS убедитесь, что его> = 0, чтобы другие единицы не выходили за пределы.

Переписать

Переписывание добавляет немного CSS, много HTML и разбивает JS на множество частей.

  • Только входное значение в градусах Кельвина определяется минимальным значением, шагом и значением. Остальные значения устанавливаются при первом запуске JavaScript путем вызова decimalEvent

  • Каждый температурный вход использует data-unit="" чтобы назвать используемую единицу. Это имя используется для поиска правильной функции преобразования в объекте. toKelvin.

  • События ввода температуры и десятичного числа разделены. Десятичный прослушиватель вызовет прослушиватель температуры, который будет использовать целевой по умолчанию в градусах Кельвина при вызове без события.

const F_SCALE = 1.8, F_OFFSET = 459.67;
const C_OFFSET = 273.15;
const toKelvin = {
    Celsius:   t => t + C_OFFSET,
    Farenheit: t => (t + F_OFFSET) / F_SCALE,
    Rankine:   t => t / F_SCALE,
    Kelvin:    t => t,
};
const fromKelvin = {
    Celsius:   k => celsiusIn.value =   round(k - C_OFFSET),
    Farenheit: k => farenheitIn.value = round(k * F_SCALE - F_OFFSET),
    Rankine:   k => rankineIn.value =   round(k * F_SCALE),
    Kelvin:    k => kelvinIn.value =    round(k),
};
const round = val => Math.round(val * round.scale) / round.scale;

decimalIn.addEventListener("input", decimalEvent);
temperatureList.addEventListener("input", temperatureEvent);
decimalEvent();

function decimalEvent() {
    const step = 1 / (round.scale = 10 ** decimalIn.value);
    celsiusIn.step = step;
    kelvinIn.step = step;
    farenheitIn.step = step;
    rankineIn.step = step;
    temperatureEvent();
} 
function temperatureEvent({target = kelvinIn} = {}) {   
    if (target.value !== "") {
        const unit = target.dataset.units;
        const kelvin = Math.max(0, toKelvin[unit](round(Number(target.value))));
        for (const convert of Object.values(fromKelvin)) { convert(kelvin) }  
    }
}
label {
    font-size: large;
}
input {
    width: 3em;
}
ul {
    width: 220px;
    display: flex;
    flex-direction: column;
    list-style-type: none;
    padding-inline-start: 0px;
}
li input {
    float: right;
    width: 7em;
}
<h3>Temperature unit converter</h3>
 <input type="number" min="0" max="5" value="0" step="1" id="decimalIn">
<label for="decimalIn"><small>Decimals<small></label>

<ul id="temperatureList">
<li>
    <label for="celsiusIn">Celsius (ºC) </label>
    <input id="celsiusIn" type="number"  data-units ="Celsius">
</li> 

<li> 
    <label for="kelvinIn">Kelvin (K) </label>
    <input id="kelvinIn" type="number" min="0" value="293" step="1" data-units="Kelvin">
</li> 

<li> 
    <label for="farenheitIn">Farenheit (ºF) </label>
    <input id="farenheitIn" type="number" data-units="Farenheit">
</li> 

<li>
    <label for="rankineIn">Rankine (ºRa) </label>
    <input id="rankineIn" type="number"  data-units="Rankine"> 
</li> 
</ul>

Обновлять

При первоначальной перезаписи было несколько проблем.

  • В некоторых ситуациях не удавалось ввести отрицательные значения
  • Преобразовывал цифры после десятичного счёта
  • Отображались нули в конце. Например 0.000 должно быть просто 0

Код был изменен, чтобы игнорировать частичные вводы. Например, отрицательный знак «-» перед добавлением чисел.

С использованием Math.round скорее, чем Number.toFixed для установки количества десятичных знаков.

Округлите десятичные дроби перед преобразованием в базовую единицу (кельвин), чтобы дробные части после десятичной дроби не изменяли другие единицы.

  • Я никогда не видел такого красивого кода и даже представить себе не мог, что можно будет сделать код таким простым. Ваши объяснения помогли мне лучше понять JavaScript, и я обязательно буду применять все, чему вы учили.

    — Арнон Родригес

  • Я только что понял, что входные данные не принимают отрицательные числа непосредственно с клавиатуры.

    — Арнон Родригес

  • 1

    @ArnonRodrigues Входы должны использовать событие изменения, а не событие входа. Однако для этого потребуется кнопка расчета. Вы также можете объединить два (события) и не устанавливать значение элемента ввода с фокусом, пока он не получит событие изменения

    — Слепой67

  • 1

    @ArnonRodrigues Я только что заметил другую проблему. Я вне времени банкомат. Завтра обновлю ответ, касающийся проблем.

    — Слепой67

  • Хорошо, @ Blindman67! Ваш код был моей основой для работы с другими системами измерения. Полный JavaScript было немного однообразно, но для меня это идеально!

    — Арнон Родригес


Использование символов, отличных от ASCII º в именах переменных меня удивляет


Много повторяется * 1 который предположительно используется для преобразования string к number. parseFloat или же parseInt сделает намерение более ясным


В формулах много повторов. Я бы получил новое введенное пользователем значение и преобразовал его в стандартный формат (например, ºC). Тогда у меня была бы одна функция для преобразования из ºC в любые другие единицы.


== следует заменить на === как только возможно


campo похоже на португальское слово «поле». Консенсус это кодирование должно быть на английском


Незначительная ошибка: увеличение числа десятичных знаков приводит к неточности (в нем указано, что 20ºC — это 293K, но должно быть 293,15K). Чтобы результаты были точными, необходимо пересчитать результаты, исходя из последнего введенного пользователем значения.


Шаг по умолчанию для input теги — 1. Этот атрибут следует изменить на any для удаления ошибок валидации.

  • Вы мне очень помогли! Я очень ценю это! Все сделанные вами предложения теперь используются! Большое спасибо!!

    — Арнон Родригес

Этот код можно значительно упростить.

Не используйте не буквенно-цифровые символы для именования идентификаторов, переменных, функций и т. Д.

Вам следует подумать об изменении способа использования десятичных знаков. Например, если вы решите использовать один десятичный знак для числа, например 2.19 ты получишь 2.1. Я ожидал, что это будет округлено до ближайшего целого числа, и это будет 2.2.

Кроме того, вы определенно можете значительно упростить код. Вот как бы я это сделал:

// for being able to keep track of the unit we are using
// type Unit = "C" | "K" | "RA" | "RO" | "N" | "DE" | "RE"

// create a helper class that does the conversion
// it's easier if you have a base unit to convert to and from. I chose
// celsius

class Convertor {
    constructor(temp, unit) {
        this.tempInCelsius = this.convertToCelsius(temp, unit);
    }

    get toCelsius() {
        return this.tempInCelsius;
    }
    get toKelvin() {
        return this.tempInCelsius + 273.15;
    }
    get toFahrenheit() {
        return (this.tempInCelsius * 1.8) + 32;
    }
    get toRankine() {
        return (this.tempInCelsius * 9/5 + 491.67).toFixed(2)
    }
    get toRomer() {
        return this.tempInCelsius * 21/40 + 7.5;
    }
    get toNewton() {
        return this.tempInCelsius * 3.0303;
    }
    get toDelisle() {
        return (100 - this.tempInCelsius) * 3/2;
    }
    get toReaumur() {
        return this.tempInCelsius * 0.8;
    }

    convertToCelsius(temp, unit) {
        switch (unit) {
            case 'C':
                return temp;
            case 'K':
                return temp - 273.15;
            case 'RA':
                return (temp - 491.67) * 5/9;
            case 'RO':
                return (temp - 7.5) * 40/21;
            case 'N':
                return temp / 3.0303;
            case 'DE':
                return 100 - (temp * 2/3);
            case 'RE':
                return temp / 0.8;
        }
    }
}

window.oninput = function(event) {
    const campo = event.target.id; 
    const i = document.getElementById("decimalTemp").value;
    // you need to rename the id's of the inputs
    // the switch inside the convertToCelsius is using that id
    const degreesCelsius = new Convertor(+(document.getElementById(campo).value), campo);
    C.value = degreesCelsius.toCelsius;
    K.value = degreesCelsius.toKelvin;
    F.value = degreesCelsius.toFahrenheit;
    RA.value = degreesCelsius.toRankine;
    RO.value = degreesCelsius.toRomer;
    N.value = degreesCelsius.toNewton;
    DE.value = degreesCelsius.toDelisle;
    RE.value = degreesCelsius.toReaumur;
  };

В своем html вы переименовываете свой идентификатор следующим образом:

<div class="block-input">
              <input id="C" type="number" min="-273.15" value="20">
              <h4>Celsius (degrees C)</h4>
            </div>
            <div class="block-input">
              <input id="K" type="number" min="0" value="293">
              <h4>Kelvin (K)</h4>
            </div>
            <div class="block-input">
              <input id="F" type="number" min="-459.67" value="68">
              <h4>Farenheit (degreesF)</h4>
            </div>
            <div class="block-input">
              <input id="RA" type="number" min="0" value="528">
              <h4>Rankine (degreesRa)</h4>
            </div>
            <div class="block-input">
              <input id="RO" type="number" min="-135.90" value="18">
              <h4>Rømer (degreesRø)</h4>
            </div>
            <div class="block-input">
              <input id="N" type="number" min="-90.14" value="7">
              <h4>Newton (degreesN)</h4>
            </div>
            <div class="block-input">
              <input id="DE" type="number" min="-559.73" value="120">
              <h4>Delisle (degreesDe)</h4>
            </div>
            <div class="block-input">
              <input id="RE" type="number" min="-218.52" value="16">
              <h4>Reaumur (degreesRe)</h4>
            </div>

Вот jsfiddle: https://jsfiddle.net/4f5nsyo8/1/

Я считаю, что Конструктор сэкономит много строк кода. В основном, когда мне нужно написать другие системы измерения. Но как сделать, чтобы десятичные дроби работали? Считаете ли вы Constructor лучшим местом для его установки?

— Арнон Родригес

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *