简体   繁体   English

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

[英]How can I keep fraction formatting using JavaScript?

My code is focused on cooking (Banana Bread recipe). 我的代码专注于烹饪(香蕉面包食谱)。 Depending on the number of people, I will sometimes make two Banana Bread's as opposed to one. 根据人数的不同,有时我会制作两种香蕉面包,而不是一种。 Thus, I use the selection tool to account for this by changing the amount of each ingredient. 因此,我使用选择工具通过更改每种成分的数量来解决这一问题。 Yet, my problem is JavaScript outputting decimals instead of fractions. 但是,我的问题是JavaScript输出小数而不是小数。 I want to keep the numbers in fractions. 我想将数字保留为零。

Ideal 理想
If 1 was selected, it would say 2 cups flour, ½ tsp salt. 如果选择1,则表示2杯面粉, 1/2茶匙盐。
If 2 was selected, it would say 4 cups flour, 1 tsp salt. 如果选择2,则表示4杯面粉,1茶匙盐。
If 3 was selected, it would say 6 cups flour, 1 ½ tsp salt. 如果选择3,则表示6杯面粉, 1.5茶匙盐。

What actually happens: 实际发生的情况:
If 1 was selected, it would say 2 cups flour, 0.5 tsp salt. 如果选择1,则表示2杯面粉,0.5茶匙盐。
If 2 was selected, it would say 4 cups flour, 1 tsp salt. 如果选择2,则表示4杯面粉,1茶匙盐。
If 3 was selected, it would say 6 cups flour, 1.5 tsp salt. 如果选择3,则表示6杯面粉,1.5茶匙盐。

Code: 码:

 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> 

Instead of assigning values a, b, c to the options 1, 2, 3, just use the latter value: it is more intuitive. 不用为选项1、2、3分配值a,b,c,而是使用后者的值:它更直观。 You can directly use that value for the multiplication instead of doing three different if blocks. 您可以直接将该值用于乘法运算,而不必执行三个不同的if块。 You can also do away with the button, since you could just respond to the change in the select-list. 您也可以取消按钮,因为您可以只响应选择列表中的更改。

For the particular display of fractions, I would suggest putting all that logic in a class, which you could call Rational . 对于分数的特定显示,我建议将所有逻辑放在一个类中,您可以将其称为Rational It would keep numerator and denominator separate and allow to do multiplication (and other operations) on it, and to display the result with the desired output format. 它将分子和分母分开,并允许对其进行乘法(和其他运算),并以所需的输出格式显示结果。 This way you isolate that formatting logic from the recipe logic. 这样,您可以将格式逻辑与配方逻辑隔离。

Here is such a Rational class: it could be easily extended to do more than multiplication (eg addition, division, negation, inversion, ...): 这是一个这样的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> 

Notice how the last function can concentrate on the recipe logic, delegating the use of fractions to the Rational class, which in turn is completely ignorant of the recipe-business. 请注意,最后一个函数如何将精力集中在配方逻辑上,将分数的使用委托给Rational类,而后者又完全不了解配方业务。

For older JS engines... 对于较旧的JS引擎...

As you comment about an error that may be related to a JS engine that does not support ES6 syntax, I add here a version of the same using old-ES3 syntax: 当您评论可能与不支持ES6语法的JS引擎相关的错误时,我在这里添加使用old-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> 

...

    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;

To representate 0.5 as a fraction you're using the html entity &frac12; 要将0.5表示为分数,您使用的是html实体&frac12; . The numberToFraction() function is actually returning a string like "1/2" though. 但是, numberToFraction()函数实际上返回的是“ 1/2”之类的字符串。

So you need to include a check if amount is 1/2 and in case it is replace it by &frac12; 因此,您需要检查金额是否为1/2,并用&frac12;替换&frac12; and return this instead. 并返回它。

Furthermore to update the span's you need to use their .innerHTML property instead of .innerText - otherwise you won't see a fraction. 此外,要更新跨度,您需要使用其.innerHTML属性而不是.innerText-否则,您将看不到分数。

Here's an example: 这是一个例子:

 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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM