一个JavaScript实现的贷款计算器

本文介绍了如何使用JavaScript来实现一个贷款计算器,涵盖了查找HTML元素、获取用户输入、设置HTML内容、存储数据、发起HTTP请求以及利用元素绘图等技术。

基于JavaScript实现的贷款计算器

本文实现的技术:

  • 如何在文档中查找元素
  • 如何通过表单Input元素来获取用户输入的数据
  • 如何通过元素来设置HTML内容
  • 如何将数据存储在浏览器中
  • 如何使用脚本发起HTTP请求
  • 如何利用元素绘图

先看成果
在这里插入图片描述

HTML部分

<table id="myTable">
    <tr>
        <th>输入贷款数据</th>
        <td></td>
        <th>贷款余额、累计权益和利息支付</th>
    </tr>
    <tr>
        <td>贷款金额 ($):</td>
        <td><input id="amount" onchange="calculate()"/></td>
        <td rowspan=8>
            <canvas id='graph' width=400 height=250></canvas>
        </td>
    </tr>
    <tr>
        <td>
            年利息(%):
        </td>
        <td><input id='apr' onchange="calculate()"/></td>
    </tr>
    <tr>
        <td>
            还款期():
        </td>
        <td><input id='years' onchange="calculate()"/></td>
    </tr>
    <tr>
        <td>
            邮政编码(查找贷方):
        </td>
        <td><input id='zipcode' onchange="calculate()"/></td>
    </tr>
    <tr>
        <td>
            接近付款:
        </td>
        <td><button onclick="calculate()">计算</button></td>
    </tr>
    <tr>
        <td>
            每月付款:
        </td>
        <td>$<span class="output" id="payment"></span></td>
    </tr>
    <tr>
        <td>
            付款总额:
        </td>
        <td>$<span class="output" id="total"></span></td>
    </tr>
    <tr>
        <td>
            总利息:
        </td>
        <td>$<span class="output" id="totalinterest"></span></td>
    </tr>
    <tr>
        <th>
            赞助商:</th><td colspan=2>
               向这些优秀的贷款人申请贷款:
            <div id="lenders"></div>
        </td>
    </tr>
</table>

CSS部分

 #myTable{
            margin: auto;         //居中
        }
        .output{
            font-weight: bolder;   //计算结果定义为粗体
        }
        #payment{
            text-decoration: underline;  //定义id为payment的元素样式
        }
        #graph{
            border: solid black 1px;     //图表有一个1像素的边框
        }
        th td{
            vertical-align: top;        //表格单元与其对齐方式为顶端对齐
        }

JS部分

function calculate(){
    // 贷款金额
    var amount = document.getElementById('amount');
    // 年利息
    var apr = document.getElementById('apr');
    // 还款期
    var years = document.getElementById('years');
    //贷款方
    var zipcode = document.getElementById('zipcode');
    // 每月支付
    var payment = document.getElementById('payment');
    // 总支付
    var total = document.getElementById('total');
    // 总利息
    var totalinterest = document.getElementById('totalinterest');

    // amount 贷款总额
    var principle = parseFloat(amount.value);
    // apr 年利率
    var interest = parseFloat(apr.value) /100 /12;
    // 偿还周期 月份
    var payments = parseFloat(years.value) * 12;

    // pow 求次幂
    var x = Math.pow(1 + interest, payments);
    // monthly 每月还款金额
    var monthly = (principle * x * interest) / (x-1);

    //如果没有超过数字范围,且用户输入也正确
    if(isFinite(monthly)){
        payment.innerHTML = monthly.toFixed(2);
        total.innerHTML = (monthly * payments).toFixed(2);
        totalinterest.innerHTML = (monthly * payments - principle).toFixed(2);

        // 保存数据到本地
        save(amount.value, apr.value, years.value, zipcode.value);

        // 借贷人,忽略网络错误
        try{
            getLenders(amount.value, apr.value, years.value, zipcode.value);
        }
        catch (e) {
            //忽略异常
        }
        // 画图
        chart(principle, interest, monthly, payments);
    }else{
        //计算结果不是数字或者无穷大,意味着输入数据是非法或不完整的
        //清空数据
        payment.innerHTML = "";
        total.innerHTML = "";
        totalinterest.innerHTML = "";
        chart();
    }
}
//将用户输入保存至localSorage对象的属性中
function save(amount, apr, years, zipcode){
    if(window.localStorage){//只有支持的浏览器才能运行这个代码
        localStorage.loan_amount = amount;
        localStorage.loan_apr = apr;
        localStorage.loan_years = years;
        localStorage.loan_zipcode = zipcode;
    }
}
//文档首次加载的时,将会尝试还原输入字段
window.onload = function(){
    //如果浏览器支持本地存储并且上次保存的值也是存在的
    if(window.localStorage && localStorage.loan_amount){
        document.getElementById('amount').value = localStorage.loan_amount;
        document.getElementById('apr').value = localStorage.loan_apr;
        document.getElementById('years').value = localStorage.loan_years;
        document.getElementById('zipcode').value = localStorage.loan_zipcode;
    }
}

//将用户的输入发送至服务器上
function getLenders(amount,apr,years,zipcode) {
    //如果浏览器不支持XMLHttpRequest对象,则退出
    if(!window.XMLHttpRequest) return;

    //找到要显示放贷人列表的元素
    var ad =document.getElementById("lenders");
    if(!ad) return; //如果为空则退出

    //将用户的输入数据进行URL编码,并将查询参数附加在URL里
    var url ="getLenders.php" + //处理数据的URL地址
    "?amt="+encodeURIComponent(amount)+ //使用查询串中的数据
    "&apr="+encodeURIComponent(apr) +
    "&yrs="+encodeURIComponent(years) +
    "&zip="+encodeURIComponent(zipcode);

    //通过XMLHttpRequest对象提取返回数据
    var req=new  XMLHttpRequest()   //发起一个新的请求
    req.open("GET",url);  //通过URL发起一个HTTP GRT请求
    req.send(null)           //不带任何正文发送这个请求

    //返回数据之前,注册一个事件处理函数,这个处理函数
    //绘制服务器的响应返回至客户端的时候调用
    //这种异步编程模型在客户端JS中是非常常见的
    req.onreadystatechange=function () {
        if(req.readyState == 4 && req.status ==200){
            //如果代码运行到这里,说明得到了以后合法且完整的HTTP响应
            var response =req.responseText;    //HTTP响应是以字符串的形式呈现的
            var lenders =JSON.parse(response)   //将其解析为JS数组

            //将数组中的贷款人对象转换为HTML字符串形式
            var list =""
            for (let i=0;i<lenders.length;i++ ){
                list +="<li><a href ='"+lenders[i].url+"'>"+
                    lenders[i].name + "</a>";
            }
            //将数据在HTML元素中呈现出来
            ad.innerHTML ="<ul>" + list +"</ul>";
        }
    }

}

//在HTML<canvas>元素中用图表展示贷款余额、利息和资产收益
//如果不传参的话则清空之前图表数据
function chart(principle, interest, monthly, payments){
    var graph = document.getElementById('graph'); //得到canvas标签
    graph.width = graph.width;    //巧妙的清除并重置画布
    //如果不传参。或者浏览器不支持画布,则直接返回
    if(arguments.length == 0||!graph.getContext) return;

    //获取画布元素的“context”对象,这个对象定义了一组绘画API
    var g = graph.getContext('2d');  //所有的绘画操作将基于这个对象

    var width = graph.width;
    var height = graph.height;    //获得画布大小

    // 将付款数字和美元数据转换为像素
    function paymentToX(n){
        return n * width / payments;
    }
    function amountToY(a){
        return  height - a * height / (monthly * payments * 1.05);
    }
    //付款数据是一条从(0,0)到(payments,monthly*payments)
    g.moveTo(paymentToX(0), amountToY(0)); //从左下开始
    g.lineTo(paymentToX(payments), amountToY(monthly * payments));//至右上
    g.lineTo(paymentToX(payments), amountToY(0)); //至右下
    g.closePath(); //将结尾链接值开头
    g.fillStyle = '#f88';   //亮红色
    g.fill(); //填充矩形
    g.font = "bold 12px sans-serif";  //定义字体
    //g.fillStyle = "yellow";
    g.fillText("利息支付总额", 20, 20);  //将文字绘制到图列中

    // 很多资产数据不是线性的,很难将其反印到图表中
    var equity = 0;
    g.beginPath();   //开始绘制图形
    g.moveTo(paymentToX(0), amountToY(0)); //左下开始

    for( var p = 1; p<=payments; p++){     //计算出每一笔赔付的利息
        var thisMonthsInterest = (principle - equity) * interest;
        equity += (monthly - thisMonthsInterest);      //得到资产额
        g.lineTo(paymentToX(p), amountToY(equity));     //将数据绘制到画布上
    }

    g.lineTo(paymentToX(payments), amountToY(0));  //将数据绘制到X轴
    g.closePath();        //将线条结尾连接至线条开头
    g.fillStyle = 'green';   //绿色
    g.fill();   //曲线下面均匀填充
    g.fillText('总权益', 20, 35);    //文本设置成绿色

    //画余额
    var bal = principle;
    g.beginPath();
    g.moveTo(paymentToX(0), amountToY(bal));
    for(var p=1; p<payments;p++){
        var thisMonthsInterest = bal*interest;
        bal-= (monthly - thisMonthsInterest);      //得到资产额
        g.lineTo(paymentToX(p), amountToY(bal));   //将直线连接至某点
    }
    g.lineWidth = 3;          //将直线宽度加粗
    g.fillStyle='black';      //使用黑色字体
    g.stroke();               //绘制余额的曲线
    g.fillText("贷款余额", 20, 50);     //图例文字

    //将年度数据在X轴做标记
    g.textAlign = 'center';     //文字居中对齐
    var y = amountToY(0);        //Y坐标设为0
    for(var year=1; year*12<=payments;year++){     //遍历每年
        var x = paymentToX(year*12);     //计算标记位置
        g.fillRect(x-0.5, y-3, 1, 3);       //开始绘制标记
        if(year ==1){                       //在坐标轴做标记
            g.fillText("0",x,y-5);
        }
        if(year % 5==0 && year*12 !== payments){     //每五年的数据
            g.fillText(String(year),x,y-5);
        }
    }
    //将赔付数额标记在右边界
    g.textAlign = "right";       //文字右对齐
    g.textBaseline = "middle";    //文字垂直居中
    g.fillStyle='black';
    var ticks = [monthly*payments, principle];        //将用到的两个点
    var rightEdge = paymentToX(payments);      //设置X坐标
    for(let i=0;i<ticks.length;i++){        //对每两个点循环
        var y = amountToY(ticks[i]);        //计算每个标记的Y坐标
        g.fillRect(rightEdge -3, y-0.5,3,1);    //绘制标记
        g.fillText(String(ticks[i].toFixed(0)), rightEdge-5, y);    //绘制文本
    }

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jet_closer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值