网站搜索

javascript - jQuery 根据两个下拉菜单和一个文本框字段计算费用的 IF 语句


这是一个费用计算器示例,它将根据用户选择和回答实时计算费用(jQuery)。我正在尝试弄清楚如何创建许多 IF 语句,以根据两个下拉菜单和一个文本框字段计算费用。

我试图实现的是一个 jQuery 的 IF 函数,当用户选择他们的出生月份时,会使用 onChange="calculateTotal()" 进行计算(计算月份),这将计算从现在起到他们下一个生日的月份数。但我需要根据车辆下拉菜单(vehiclebody)和输入的重量(ew)来设置 IF 函数,这三项将决定价格。就像下面的例子和代码片段一样。

例如(三种情况):
[1] 如果选择从现在起4-12个月,并且是重量低于2499的两门车辆,价格将为28.10,加入行驶费用计算器。
[2] 如果选择从现在起4-12个月,并且是重量在2500到3499之间的两门车辆,价格将为36.10,加入行驶费用计算器。
[3] 如果选择从现在起4-12个月,并且是重量大于3500的两门车辆,价格将为46.10,加入行驶费用计算器。

长话短说,我想要一个 IF 函数来计算 onChange="calculateTotal()" 和 var titleFees=getProofOfOwnership() + (New IF Function);,具体取决于所选择的 (vehiclebody) 和输入的 (ew);然后,如果 (monthsToGo) 等于 4 到 12,价格就是某某价格。如果 (monthsToGo) 是 1、2、3、13、14 或 15,价格将按比例计算,因此也会有其自己的价格。

如果还有1个月,他们要求用户支付那个月和整整一年的费用,所以总共13个月,但如果还有2个月,他们让用户选择支付2个月或14个月,3个月同理选择3个月或15个月(如你在“计算月份”下拉菜单中看到的),但是一旦是4个月(无论是4-12个月,他们都要求支付全额)。

可怕的是,我将不得不弄清大约50种不同的组合,所以希望即使我对jQuery知识极度缺乏,我也能容易理解。

任何帮助都将非常、非常、非常感激!! :)

http://jsfiddle.net/fzy9yev3/15/

请参见下面的片段:

//Calculate Months
(function() {
    var monthsToGo;
    var Fee = makeStruct("monthSect vehicleBody ewSect price");
    var fees = [
        new Fee(/*monthSect*/2, /*vehicleBody*/0, /*ewSect*/0, /*price*/45.10),
        new Fee(3, 1, 0, 55.10),
        new Fee(4, 2, 0, 65.10),
        new Fee(13, 3, 0, 75.10),
        new Fee(14, 4, 0, 85.10),
        new Fee(15, 5, 0, 95.10)
    ];

    $(document).ready(function() {
        $('#month2, #month3').hide();
    });
    
    $(document).on('change', '#ownership input', function(){
        calculateTotal();
        //statedropDown($(this).val());
    });
    
    $(document).on('change', '#month1', function() {
        // ignore blank options
        if ($(this).val() == '') { return; }
        
        var vehicle = $('#vehiclebody').val();
        var ew = $('#ew').val();
        var ewSect = 0;
        var monthSect = 0;
        var titleFees = 0;
        
        if(vehicle == '' || ew == ''){
            alert('Please enter Vehicle Type and/or Empty Weight');
            $(this).val('');
            return;
        }
        
        var today = new Date();
        var birthdate = new Date();
        birthdate.setMonth($('#month1').val());

        monthsToGo = (today.getMonth() < birthdate.getMonth())
            ? birthdate.getMonth() - today.getMonth()
            : (12 - today.getMonth()) + birthdate.getMonth()
        ;
        
        $('#month2').hide();
        $('#month3').hide();

        if (monthsToGo == 1) {
            this.monthsToGo = 13;
            alert(this.monthsToGo);
        } else if (monthsToGo == 2) {
            $('#month2').show();
        } else if (monthsToGo == 3) {
            $('#month3').show();
        } else {
            this.monthsToGo = monthsToGo;
            alert(this.monthsToGo);
        }
        
        if(monthsToGo >= 4 || monthsToGo <= 12){
            monthSect = 4;
            //Set monthsToGo to 4 if it is in this range for the linked list so
            //categorizing is easier
            //6 possibilities for dates -- 2, 3, 4, 13, 14, 15
        }
        else monthSect = monthsToGo;
        
        switch(vehicle){
            case 0://2dr
            case 2://4dr
            case 4://convertible
            case 5://van
                if(ew < 2500) ewSect = 0;
                else if(ew >= 2500 && ew < 3500) ewSect = 1;
                else if(ew >= 3500) ewSect = 2;
                break;
            case 1://pickup
                if(ew < 2000) ew = 0;
                else if(ew >= 2000 && ew <= 3000) ewSect = 1;
                else if(ew > 3000 && ew <= 5000) ewSect = 2;
                break;
            case 3://trucks
                if(ew > 5000 && ew < 6000) ewSect = 0;
                else if(ew >= 6000 && ew < 8000) ewSect = 1;
                else if(ew >= 8000 && ew < 10000) ewSect = 2;
                else if(ew >= 10000 && ew < 15000) ewSect = 3;
                else if(ew >= 15000 && ew < 20000) ewSect = 4;
                else if(ew >= 20000 && ew <= 26000) ewSect = 5;
                else if(ew > 26000 && ew < 35000) ewSect = 6;
                else if(ew >= 35000 && ew < 44000) ewSect = 7;
                else if(ew >= 44000 && ew < 55000) ewSect = 8;
                else if(ew >= 55000 && ew < 62000) ewSect = 9;
                else if(ew >= 62000 && ew < 72000) ewSect = 10;
                else if(ew >= 72000 && ew <= 8000) ewSect = 11;
                break;
        }
        
        console.log('Month Section (monthSect): ' + monthSect + '; Vehicle: ' + vehicle + '; EW Section (ewSect): ' + ewSect);
        
        for(var i = 0; i < fees.length; i++){
            console.log('infor');
            if(fees[i].monthSect == monthSect && fees[i].vehicleBody == vehicle && fees[i].ewSect == ewSect) {
                titleFees = getProofOfOwnership() + fees[i].price;
                console.log('Title Found! ' + titleFees);
                $('#totalPrice').text('Estimated Transfer Fees $' + titleFees);
                break;
            }
        }
        
    });

    $('#month2, #month3').on('change', function() {
        this.monthToGo = $(this).val();
        alert(this.monthToGo);
    });
    
}($))

//Fee Calculator
//Setting Proof of Ownership Prices
 //Set up an associative array
 var title_prices = new Array();
 title_prices["MCO"]=68.25;
 title_prices["FL Title"]=78.25;
 title_prices["OOS Title"]=88.25;
 
 // Proof of Ownership Radio Buttons
function getProofOfOwnership()
{  
    var proofOfOwnership=0;
    //Get a reference to the form id="form"
    var theForm = document.forms["form"];
    //Get a reference to the title the user Chooses name=ownerShip":
    var ownerShip = theForm.elements["ownership"];
    //Here since there are 4 radio buttons ownerShip.length = 4
    //We loop through each radio buttons
    for(var i = 0; i < ownerShip.length; i++)
    {
        //if the radio button is checked
        if(ownerShip[i].checked)
        {
            proofOfOwnership = title_prices[ownerShip[i].value];
            //If we get a match then we break out of this loop
            //No reason to continue if we get a match
            break;
        }
    }
    //We return the proofOfOwnership
    return proofOfOwnership;
}
function calculateTotal()
{

    var titleFees = getProofOfOwnership();
    


    var divobj = document.getElementById('totalPrice');
    divobj.style.display='block';
    divobj.innerHTML = "Estimated Transfer Fees $"+titleFees;

}

function hideTotal()
{
    var divobj = document.getElementById('totalPrice');
    divobj.style.display='none';
}

function makeStruct(names) {
  var names = names.split(' ');
  var count = names.length;
  function constructor() {
    for (var i = 0; i < count; i++) {
      this[names[i]] = arguments[i];
    }
  }
  return constructor;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<form name="form">
    <div id="ownership">
        <label class='radiolabel'><input type="radio"  name="ownership" required="yes" message="Please select proof of ownership." value="MCO"/>Manufacturer's Statement of Origin&nbsp;&nbsp;</label><br/>
        <label class='radiolabel'><input type="radio"  name="ownership" value="FL Title"/>Florida Certificate of Title&nbsp;&nbsp;</label><br/>
                <label class='radiolabel'><input type="radio"  name="ownership" value="OOS Title"/>Out-of-state Certificate of Title&nbsp;&nbsp;</label>
        </div>

    <br/>
    <br/>

<label for='month1'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calculate Months:</label>
<select name="month1" id="month1" size="1">
    <option value="">Choose a Month</option>
    <option value="0">January</option>
    <option value="1">February</option>
    <option value="2">March</option>
    <option value="3">April</option>
    <option value="4">May</option>
    <option value="5">June</option>
    <option value="6">July</option>
    <option value="7">August</option>
    <option value="8">September</option>
    <option value="9">October</option>
    <option value="10">November</option>
    <option value="11">December</option>
</select>
<select name="month2" id="month2" size="1">
    <option value="">Choose an Option</option>
    <option value="2">2</option>
    <option value="14">14</option>
</select>
<select name="month3" id="month3" size="1">
    <option value="">Choose an Option</option>
    <option value="3">3</option>
    <option value="15">15</option>
</select>
    <br/>
    

<select name="vehiclebody" id="vehiclebody" required="yes" message="Please select body." size="1">
    <option value="">Choose a Vehicle</option>
    <option value="0">2Dr</option>
    <option value="1">Pickup</option>
    <option value="2">4dr</option>
    <option value="3">Truck</option>
    <option value="4">Convertible</option>
    <option value="5">Van</option>
</select>

<label for="ew">Empty Weight:</label>
    <input type="text" name="ew" id="ew"/>
    <br/>
    <br/>
    <div id="totalPrice"></div>
</form>

答案#1

我建议采取一种方法,不仅可以清理你的代码,还可以让计算、测试、验证和添加新功能变得更容易。稍微清理一下可以在很大程度上让你的应用更容易扩展和调试,但更重要的是,对于你的情况,稍微清理一下将帮助你计算所需的数值,并以直接的方式解决你的问题。

建议 #01:整理你的代码

目前,你有一些函数试图一次完成过多的任务。如果保持函数简单,让每个函数专注于特定的功能,函数会更容易测试和调试。例如,在你的 on.("change") 处理器中,对于 $("#month1") 下拉菜单,你试图一次完成所有事情,这正是你遇到问题的原因。相反,你应该给 #month1 下拉菜单分配一个 .on("change") 处理器,该处理器将确定是否需要显示 #month2 或 #month3,然后分配一个单独的 使用 on("change") 处理程序来收集这两个下拉列表的值。在此过程中,你还应该将任何“专门的”功能拆分到自己的函数中,以保持代码整洁。

一个你的 #month1
change 处理程序的示例,它只是试图一次做太多事情:

$(document).on('change', '#month1', function() {
    // 1. Stop if Empty Weight or Vehicle Type are Blank
    // 2. Get the user's birth month
    // 3. Calculate the number of months until the user's Birthday
    // 4. Calculate the monthSect value
    // 5. Calculate the ewSect value
    // 6. Lookup the Proof of Ownership Fees
    // 7. Lookup prorated Title Fees
});

相反,与其让这个函数尝试在一个地方执行所有这些任务,你最好将任何“专门的”功能移动到简单、易理解的函数中,每个函数都有明确的目的。你可以创建如下的函数名:

// Lookup the Prorated Fee
getProratedFeeFromFeeList(monthSect, vehicleBody, ewSect);

// Get the "Payment Plan Details" based on user's birth month
getPaymentPlanDetailsBasedOnBirthMonth(birthMonth);

// Lookup the ewSect (Empty Weight Section)
getWeightSectionFromVehicleClassAndEmptyWeight(vehicleClass, emptyWeight);

注意:我喜欢使用长而描述性的函数名,这样函数的目的就非常清楚,从而提高代码的可读性。如果你使用具有良好代码补全功能的代码编辑器,像这样的长函数名不会增加太多额外的输入,但对我而言,我个人喜欢高度可读、自我文档化代码的好处。

建议 #02:将你的表单值存储在一个地方。

继续建议 #1,由于你的表单需要有一个“实时统计”,如果你有一个系统来随时保存表单数值的快照,将会为你省去很多麻烦。你可以用一个 Javascript 对象轻松做到这一点。

这在很多方面都很方便:

  1. 它使所有表单值“全局可用”而不会弄乱全局命名空间。
  2. 它使你的表单值在 calculateTotal() 函数中容易“计算”,因为你只需查询这个对象即可获取要代入公式的值。
  3. 您始终拥有整个表单的“实时快照”。这在测试、调试、验证或将表单结果打印到控制台或浏览器时非常方便。
  4. 它允许你在不打断工作流程的情况下,继续为你的费用计算器应用添加功能/数值。
  5. 通过始终拥有完整的快照,将更容易发现功能上的错误,并观察您的个人输入如何影响其他输入或整体计算。

所以我会创建一个名为 FC(“Fee Calculator”的缩写)的全局对象,用于存储运行费用计算所需的所有值。像这样创建这个“费用计算器对象”:

var FC = FC || {};

现在这个 FC 对象将对所有能够访问 FC 范围的函数可用。向你的 FC 对象添加值可以通过两种方式之一完成:

// First method: In FC's Declaration
var FC = { monthSect: 0, vehicleBody: null };

// Second Method: Using dot notation
var FC = {};
FC.monthSect = 0;
FC.vehicleBody = null;

注意:请记住,你始终可以使用点表示法为已经声明的对象赋值,因此这两种方法的组合是完全有效的。

现在你可以使用点表示法更新和读取你的 FC 对象的值,例如:

// Get the monthSect variable
var monthSect = FC.monthSect;

// Assign or update FC.monthSect
FC.monthSect = someNewValue; 

我对你问题的解决方案

使用我上面提到的一些建议,这就是我解决你问题的方法:

步骤 #01:每个表单输入都会监听变化,更新 FC 并调用 calculateTotal()

// When the user updates the #month2 or #month3 dropdown
// Update FC.monthSect 
$(document).on('change', '#month2, #month3', function() {
    FC.monthSect = $(this).val();
    calculateTotal();
});

// When someone updates the Empty Weight value
// update FC.emptyWeight 
$(document).on('change blur keyup', '#ew', function() {

    var emptyWeight = $(this).val();
    FC.emptyWeight = emptyWeight ? emptyWeight : null;

    var vehicle = $('#vehiclebody').val();

    if (vehicle && emptyWeight) {
        FC.ewSect = FCUtils.getWeightSectionFromVehicleClassAndEmptyWeight(FC.vehicleBody, FC.emptyWeight);
         FCUtils.getProratedFeeFromFeeList(FC.monthSect, FC.vehicleBody, FC.ewSect);
    }

    calculateTotal();

});


// When the user updates the #month1 drop-down 
// Update FC.monthSect and assign FC.proratedPrice
$(document).on('change', '#month1', function() {

    // Reset to the defaults
    $("#month2").hide();
    $("#month3").hide();
    FC.monthSect = null;

    // ignore blank options
    if ($(this).val() == '') {
        calculateTotal();
        return;
    };

    var selecteduserBirthday = $(this).val();

    var paymentPlanDetails = FCUtils.getPaymentPlanDetailsBasedOnBirthMonth(selecteduserBirthday);
    var monthsToGo = paymentPlanDetails.monthsUntilBirthday;

    if (paymentPlanDetails.paymentPlan == "2or14months") {
        $("#month2").show();
    } else if (paymentPlanDetails.paymentPlan == "3or15months") {
        $("#month3").show();
    }

    // Assign FC.monthSect if monthSect = 4-12 | 1 | 13
    if (monthsToGo >= 4 && monthsToGo <= 12) {
        FC.monthSect = 4;
    } else if (monthsToGo == 1 || monthsToGo == 13) {
        FC.monthSect = 13;
    }

    FCUtils.getProratedFeeFromFeeList(FC.monthSect, FC.vehicleBody, FC.ewSect);
    calculateTotal();

});

注意:你可能已经注意到,有些函数名称前面加上了 FCUtils,这是一个我将所有“工具”函数附加到的对象。你在自己的程序中不一定需要这样做,你可以像平常一样编写函数并调用它们,但在我的示例应用中,我使用了一种叫做揭示模块模式(The Revealing Module Pattern)的设计模式,这有助于将常用功能进行分组,并且是让代码更易读的又一步。

第 #02 步:在 calculateTotal() 中查询 FC 对象

现在你的表单输入是自包含的,并且它们都知道如何在 FC 对象上更新各自的值,你的 calculateTotal() 函数需要做的就是查询 FC 对象的值来进行计算:

function calculateTotal() {

    var titleFees =     FC.rvPrice + 
                        FC.titlePrice + 
                        FC.lienPrice + 
                        FC.purchaseDatePrice + 
                        FC.IRFPrice + 
                        FC.proratedPrice + 
                        FC.specialFee;

    FC.totalPrice = titleFees;

    // Now you can update the browser with this data
    $("#totalPrice").text(titleFees);

}

由于 calculateTotal() 函数在表单的每个“change”事件上都会被调用,它正是赋予你的表单这种“实时”感觉的原因。你也可以在这个函数中更新应用程序的其他部分。

您可以 在这里查看我将所有这些想法付诸实践的 jsfiddle。我添加了一个 HUD(出现在右上角的“黑盒子”),它会随时为您提供 FC 对象中数据的实时快照。如果 HUD 阻碍了视线,只需“点击拖动”它,将其移动到屏幕的其他位置即可。

希望这能帮到你!祝你好运!

答案#2

当你不想手动输入一个庞大的 IF-ELSE 时,你已经走在正确的轨道上——尤其是如果它变得重复。(你在最后一行已经漏了一个“0”,而且有时是“>”,有时是“>=”:-)。

你可以做的是设置一种方法来保存不同的阈值以及阈值被突破时的数值。所以是编写算法而不是用例。你甚至可以更有创意,例如将 this.get=function(wt) 改为 this.get=function(wt, default_value) 并插入一个默认值。如此类推。

var LevelFinder = function(){
    this.range = []; // always sorted when new values added
    this.add = function( over_wt, sel_value ) {
        this.range.push({over_wt:over_wt, sel_value:sel_value});
        this.range.sort(function(x,y){return x.over_wt - y.over_wt;});
    };
    this.get = function(wt){
        var x, i;
        for ( i = 0; i < this.range.length; ++i ) {
            if ( this.range[i].over_wt > wt ) {
                if ( i > 0 ) x = this.range[i-1].sel_value;
                return x;
            }
        }
        return this.range[i-1].sel_value;
    }
} ;
var ewFinder = new LevelFinder();
ewFinder.add(10000, 3);
ewFinder.add(20000, 5);
ewFinder.add(26000, 6);
ewFinder.add(15000, 4); // this is entered out of sequence but will get sorted by the adder

ewFinder.get(17000); // produces 4 in console
ewFinder.get(22000); // 5
ewFinder.get(0); // undefined
ewFinder.get(999000); // 6

希望对你有帮助。