<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基于JavaScript实现的贷款计算器</title>
<style>
/*这是一个css样式表:定义看程序输出的样式*/
.output {font-weight: bold;}
#payment {text-decoration: underline;}
#graph{border: solid black 1px}
th ,td {
vertical-align: top;
}
</style>
</head>
<body>
<table>
<tr>
<th>
输入贷款数据:
</th>
<td></td>
<th>贷款余额,累计权益和利息支付</th>
</tr>
<tr>
<td>贷款额($):</td>
<!--onchange 事件会在域的内容改变时发生。-->
<td><input id="amount" onchange="calculate()"></td>
<!--rowspan 属性规定单元格可横跨的行数。-->
<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>
<th>近似付款:</th>
<td>
<button onclick="calculate()">计算</button>
</td>
</tr>
<tr>
<td>每月支付:</td>
<td>$<span class="output" id="payment"></span></td>
</tr>
<tr>
<td>总付款:</td>
<td>$<samp class="output" id="total"></samp></td>
</tr>
<tr>
<td>总利息:</td>
<td>$<span class="output" id="totalinterset"></span></td>
</tr>
<tr>
<td>赞助商:</td>
<td colspan="2">
向这些优良贷款人申请贷款:
<div id="lenders"></div>
</td>
</tr>
</table>
<script>
"use strict"; //如果浏览器支持的话,则开始ECMAScript5的严格模式
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 totalinterset = document.getElementById("totalinterset");
var principal = parseFloat(amount.value); //将百分比格式转换成小数格式
var interest = parseFloat(apr.value) / 100 / 12;//年利率转换成月利率
var payments = parseFloat(years.value) * 12;//将年度赔付转换成月度赔付
//现在计算月度赔付的数据
var x = Math.pow(1 + interest, payments);//进行幂运算
var monthly = (principal * x * interest) / (x - 1);
// isFinite() 函数用于检查其参数是否是无穷大。
if (isFinite(monthly)) {
//将数据填充至输出字段的位置,四舍五入到小数点后两位数字
payment.innerHTML = monthly.toFixed(2); //toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。
total.innerHTML = (monthly * payments).toFixed(2);
totalinterset.innerHTML = ((monthly * payments) - principal).toFixed(2);
//将用户的输入数据保存下来,这样下次访问时也能取到数据
save(amount.value, apr.value, years.value, zipcode.value);
//找到并展示本地放贷人,但忽略网络错误
try {
//捕获这段代码抛出的所有异常
getLenders(amount.value, apr.value, years.value, zipcode.value);
}
catch (e) {
// 忽略这些异常
}
//最后,用图表展示贷款余额,利息个资产收益
chart(principal, interest, monthly, payments)
} else {
//计算结果不是数组或者视无穷大,意味着输入数据是非法或者不完整的清空之前的输出数据
payment.innerHTML = "";
total.innerHTML = "";
totalinterset.innerHTML = "";
chart();
}
}
//将用户的输入保存至localStorage对象的属性中
//这些属性在再次访问时还会继续保持在原位置
//如果你在浏览器中按照file://URL的方式直接打开本地文件
//则无法在某些浏览器中使用存储功能比如firefox
//而通过HTTP打开文件是可行的
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 GET请求
req.send(null); //不带任何正文发送这个请求
//在返回数据之前,注册了一个事件处理函数,这个处理函数将会在服务器的响应
//返回至客户端的时候调用,这种异步编程模型在客户端JavaScript中是非常常见的
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 (var i = 0; i < lenders.length; i++) {
list += "<li><a href='" + lenders[i].url + "'>" + lenders[i].name + "</a></li>"
}
//将数据在HTML元素中呈现出来
ad.innerHTML = "<ul>" + list + "</ul>";
}
}
}
//在HTML<canvas>元素中用图表展示月度贷款余额,利息和资产收益
//如果不传入参宿的话,则清空之前的图表数据
function chart(principal, interest, monthly, payments) {
var graph = document.getElementById("graph"); //得到<canvas>
graph.width = graph.width; //用一种巧妙的手法清楚并重置画布
//获取画布元素的"context"对象,这个对象定义了一组会话API
var g = graph.getContext("2d"); //所有的绘画操作都将基于这个对象
var width = graph.width,
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.fillText("总利息支付", 20, 20); //将文字回执到图例中
//很多资产数据并不是线性的,很难将其反应至图表中
var equity = 0;
g.beginPath(); //开始绘制新的图形
g.moveTo(paymentToX(0), amountToY(0));
for (var p = 1; p <= payments; p++) {
// 计算出每一笔赔付的利息
var thisMonthsInterest = (principal - 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 = principal;
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.stroke(); //绘制余额曲线
g.fillStyle = "black"; //使用黑色字体
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("正确", x, y - 5);
if (year % 5 == 0 && year * 12 !== payments) {
g.fillText(String(year), x, y - 5);
}
g.textAlign = "right"; //文字右对齐
g.textBaseline = "middle"; //文字垂直居中
var ticks = [monthly * payments, payments];
var rightEde = paymentToX(payments);
for (var i = 0; i < ticks.length; i++) {
var y = amountToY(ticks[i]);
g.fillRect(rightEde - 3, y - 0.5, 3, 1);
g.fillText(String(ticks[i].toFixed(0)), rightEde - 5, y);
}
}
}
</script>
</body>
</html>
基于javascript实现的贷款计算器
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- GraphQL是什么? GraphQL [http://graphql.org/]是Facebook开发的一个应用...
- 学完本篇文章,你会感觉你很想写自动点击方式的外挂了,就是这么爽,这么简单,锁屏 点击 都那么easy. 简单的测试...