如何使用JavaScript保持分数格式?

时间:2019-06-13 19:22:21

标签: javascript html

我的代码专注于烹饪(香蕉面包食谱)。根据人数的不同,有时我会制作两种香蕉面包,而不是一种。因此,我使用选择工具通过更改每种成分的数量来解决这一问题。但是,我的问题是JavaScript输出小数而不是小数。我想将数字保留为零。

理想
如果选择1,则表示2杯面粉, 1/2 茶匙盐。
如果选择2,则表示4杯面粉,1茶匙盐。
如果选择3,则表示6杯面粉,茶匙盐。

实际发生的情况:
如果选择1,则表示2杯面粉,0.5茶匙盐。
如果选择2,则表示4杯面粉,1茶匙盐。
如果选择3,则表示6杯面粉,1.5茶匙盐。

代码:

document.getElementById("button").addEventListener("click", onButtonClick);

function onButtonClick() {
  document.getElementById("amount").innerText = 2;
  document.getElementById("amount2").innerText = 1 / 2;
  var n1 = document.getElementById("amount").innerText;
  var n2 = document.getElementById("amount2").innerText;
  var selection = document.getElementById("quantity").value;

  if (selection === 'a') {
    document.getElementById('amount').innerText = n1;
    document.getElementById('amount2').innerText = numberToFraction(n2);
  }

  if (selection === 'b') {
    document.getElementById('amount').innerText = n1 * 2;
    document.getElementById('amount2').innerText = n2 * 2;
  }

  if (selection === 'c') {
    document.getElementById('amount').innerText = n1 * 3;
    document.getElementById('amount2').innerText = numberToFraction(n2 * 3)
  }
}

var numberToFraction = function(amount) {
  // This is a whole number and doesn't need modification.
  if (parseFloat(amount) === parseInt(amount)) {
    return amount;
  }
  // Next 12 lines are cribbed from https://stackoverflow.com/a/23575406.
  var gcd = function(a, b) {
    if (b < 0.0000001) {
      return a;
    }
    return gcd(b, Math.floor(a % b));
  };
  var len = amount.toString().length - 2;
  var denominator = Math.pow(10, len);
  var numerator = amount * denominator;
  var divisor = gcd(numerator, denominator);
  numerator /= divisor;
  denominator /= divisor;
  var base = 0;
  // In a scenario like 3/2, convert to 1 1/2
  // by pulling out the base number and reducing the numerator.
  if (numerator > denominator) {
    base = Math.floor(numerator / denominator);
    numerator -= base * denominator;
  }
  amount = Math.floor(numerator) + '/' + Math.floor(denominator);
  if (base) {
    amount = base + ' ' + amount;
  }
  return amount;
};
<label> How many Banana Bread's are you making? </label>
<!-- Selection -->
<select id="quantity">
  <option value="a">1</option>
  <option value="b">2</option>
  <option value="c">3</option>
</select><br><br>


<!-- Button -->
<button id="button" type="button">Let's get started!</button><br><br>


<!-- HTML Recipe -->
<p>

  Step 1: Add
  <span id="amount">2</span> cups flour and
  <span id="amount2"> &frac12;</span> tsp salt into a large, dry bowl.
</p>

3 个答案:

答案 0 :(得分:2)

不用为选项1、2、3分配值a,b,c,而是使用后者的值:它更直观。您可以直接使用该值进行乘法运算,而不必执行三个不同的if块。您也可以取消按钮,因为您可以只响应选择列表中的更改。

对于分数的特定显示,我建议将所有逻辑放在一个类中,您可以将其称为Rational。它将分子和分母分开,并允许对其进行乘法(和其他运算),并以所需的输出格式显示结果。这样,您就可以将格式化逻辑与配方逻辑隔离开来。

这里有一个Rational类:可以很容易地扩展为除乘法之外(例如加法,除法,求反,求反,...):

const gcd = (a, b) => b ? gcd(b, a % b) : a;

class Rational {
    constructor(num, denom = 1) {
        if (num % 1 || denom % 1) throw "Rational constructor should get integer value(s)";
        this.num = num * Math.sign(denom);
        this.denom = Math.abs(denom);
    }
    mul(b) {
        if (typeof b === "number") b = new Rational(b);
        const denom1 = gcd(this.denom, b.num);
        const denom2 = gcd(this.num, b.denom);
        return new Rational((this.num / denom2) * (b.num / denom1), (this.denom / denom1) * (b.denom / denom2));
    }
    toString() {
        const sgn = this.num < 0 ? "-" : "";
        const n = Math.abs(this.num);
        const i = Math.trunc(n / this.denom);
        const rem = (n % this.denom);
        const frac = rem ? rem + "/" + this.denom : "";
        const remainder = {
            "1/2": "½", "1/3": "⅓", "2/3": "⅔", "1/4": "¼", "3/4": "¾",
            "1/5": "⅕", "2/5": "⅖", "3/5": "⅗", "4/5": "⅘",
            "1/6": "⅙", "5/6": "⅚", "1/7": "⅐", "1/8": "⅛",
            "3/8": "⅜", "5/8": "⅝", "7/8": "⅞", "1/9": "⅑", "1/10": "⅒"
        }[frac] || frac && ((i ? "+" : "") + frac);
        return sgn + (i || !remainder ? i : "") + remainder;
    }
}

document.getElementById("quantity").addEventListener("change", onSelectionChange);
var n1 = new Rational(2);
var n2 = new Rational(1, 2);

function onSelectionChange() {
    var selection = +document.getElementById("quantity").value;
    document.getElementById('amount').textContent = n1.mul(selection);
    document.getElementById('amount2').textContent = n2.mul(selection);
}
<label>How many Banana Bread's are you making?</label>
<!-- Selection -->
<select id="quantity">
  <option>1</option>
  <option>2</option>
  <option>3</option>
</select><br><br>

<!-- HTML Recipe -->
<p>
    Step 1: Add 
    <span id="amount">2</span> cups flour and 
    <span id="amount2">&frac12;</span> tsp salt into a large, dry bowl.
</p>

请注意最后一个功能如何集中于配方逻辑,将分数的使用委托给Rational类,而这又完全不涉及配方业务。

对于较旧的JS引擎...

当您评论可能与不支持ES6语法的JS引擎相关的错误时,我在此处添加使用旧ES3语法的相同版本:

function gcd (a, b) {
    return b ? gcd(b, a % b) : a;
}

function Rational(num, denom) {
    if (!denom) denom = 1;
    if (num % 1 || denom % 1) throw "Rational constructor should get integer value(s)";
    this.num = num * Math.sign(denom);
    this.denom = Math.abs(denom);
}

Rational.prototype.mul = function (b) {
    if (typeof b === "number") b = new Rational(b);
    var denom1 = gcd(this.denom, b.num);
    var denom2 = gcd(this.num, b.denom);
    return new Rational((this.num / denom2) * (b.num / denom1), (this.denom / denom1) * (b.denom / denom2));
}
Rational.prototype.toString = function () {
    var sgn = this.num < 0 ? "-" : "";
    var n = Math.abs(this.num);
    var i = Math.floor(n / this.denom);
    var rem = (n % this.denom);
    var frac = rem ? rem + "/" + this.denom : "";
    var remainder = {
        "1/2": "½", "1/3": "⅓", "2/3": "⅔", "1/4": "¼", "3/4": "¾",
        "1/5": "⅕", "2/5": "⅖", "3/5": "⅗", "4/5": "⅘",
        "1/6": "⅙", "5/6": "⅚", "1/7": "⅐", "1/8": "⅛",
        "3/8": "⅜", "5/8": "⅝", "7/8": "⅞", "1/9": "⅑", "1/10": "⅒"
    }[frac] || frac && ((i ? "+" : "") + frac);
    return sgn + (i || !remainder ? i : "") + remainder;
}

document.getElementById("quantity").addEventListener("change", onSelectionChange);
var n1 = new Rational(2);
var n2 = new Rational(1, 2);

function onSelectionChange() {
    var selection = +document.getElementById("quantity").value;
    document.getElementById('amount').textContent = n1.mul(selection);
    document.getElementById('amount2').textContent = n2.mul(selection);
}
<label>How many Banana Bread's are you making?</label>
<!-- Selection -->
<select id="quantity">
  <option>1</option>
  <option>2</option>
  <option>3</option>
</select><br><br>

<!-- HTML Recipe -->
<p>
    Step 1: Add 
    <span id="amount">2</span> cups flour and 
    <span id="amount2">&frac12;</span> tsp salt into a large, dry bowl.
</p>

答案 1 :(得分:0)

...

    amount = Math.floor(numerator) + '/' + Math.floor(denominator);
    //EDIT
    switch (amount) {
        case '1/4':
            amount = '&frac14;';
        break;
        case '1/3':
            amount = '&‌#8531;';
        break;
        case '1/2':
            amount = '&frac12;';
        break;
        case '2/3':
            amount = '&‌#8532;';
        break;
        case '3/4':
            amount = '&frac34;';
        break;
        default:
            amount = amount;
        break;
    }
    //END OF EDIT
    if ( base ) {
        amount = base + ' ' + amount;
    }
    return amount;

答案 2 :(得分:0)

要使用小数表示0.5,请使用html实体&frac12;。实际上, numberToFraction()函数返回的字符串类似于“ 1/2”。

因此,您需要检查金额是否为1/2,并用&frac12;替换,然后返回。

此外,要更新范围,您需要使用其 .innerHTML 属性而不是 .innerText -否则,您将看不到分数。

这是一个例子:

document.getElementById("button").addEventListener("click", onButtonClick);

function onButtonClick() {
  document.getElementById("amount").innerText = 2;
  document.getElementById("amount2").innerText = 1 / 2;
  var n1 = document.getElementById("amount").innerText;
  var n2 = document.getElementById("amount2").innerText;
  var selection = document.getElementById("quantity").value;

  if (selection === 'a') {
    document.getElementById('amount').innerText = n1;
    document.getElementById('amount2').innerHTML = numberToFraction(n2);
  }

  if (selection === 'b') {
    document.getElementById('amount').innerText = n1 * 2;
    document.getElementById('amount2').innerHTML = n2 * 2;
  }

  if (selection === 'c') {
    document.getElementById('amount').innerText = n1 * 3;
    document.getElementById('amount2').innerHTML = numberToFraction(n2 * 3)
  }
}

var numberToFraction = function(amount) {
  // This is a whole number and doesn't need modification.
  if (parseFloat(amount) === parseInt(amount)) {
    return amount;
  }
  // Next 12 lines are cribbed from https://stackoverflow.com/a/23575406.
  var gcd = function(a, b) {
    if (b < 0.0000001) {
      return a;
    }
    return gcd(b, Math.floor(a % b));
  };
  var len = amount.toString().length - 2;
  var denominator = Math.pow(10, len);
  var numerator = amount * denominator;
  var divisor = gcd(numerator, denominator);
  numerator /= divisor;
  denominator /= divisor;
  var base = 0;
  // In a scenario like 3/2, convert to 1 1/2
  // by pulling out the base number and reducing the numerator.
  if (numerator > denominator) {
    base = Math.floor(numerator / denominator);
    numerator -= base * denominator;
  }
  amount = Math.floor(numerator) + '/' + Math.floor(denominator);
  if (amount == "1/2") {
    amount = "&frac12;"
  }
  if (base) {
    amount = base + ' ' + amount;
  }

  return amount;
};
<label> How many Banana Bread's are you making? </label>


<!-- Selection -->
<select id="quantity">
  <option value="a">1</option>
  <option value="b">2</option>
  <option value="c">3</option>
</select><br><br>


<!-- Button -->
<button id="button" type="button">Let's get started!</button><br><br>


<!-- HTML Recipe -->
<p>

  Step 1: Add
  <span id="amount">2</span> cups flour and
  <span id="amount2"> &frac12;</span> tsp salt into a large, dry bowl.
</p>