最近朋友买房,想计算下自己的房贷的还款情况,自己正好周末没事,从网上找来点代码修改,也算是对自己技术的巩固吧。

目前这个还只是个初级版本,暂时可以在PC上正常访问,将来会一步一步的把相继功能都加上的,将要完成的功能:

  1. 可以在Android手机上访问的界面对齐、美化等。
  2. 图表的优化。
  3. 等额本金法和等额本息法的实现。

以上功能暂列这么多,以后有想到的在慢慢往上加;也希望大家多多的提出你的意见。

以后会把每次都更新版本都添加到文章的后面,方便历史版本的追溯。样图:


版本一:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>JS计算器,贷款利率计算器</title>
<!--参考出处:http://www.codefans.net/jscss/code/3613.shtml--> <style> /* 这是一个CSS样式表:定义了程序输出的样式 */
body{ font-size:12px;}
#payment { text-decoration: underline; } /* 定义 id="payment" 的元素样式 */
#graph { border: solid black 1px; } /* 图表有一个1像素的边框 */
th, td {vertical-align: top; } /* 表格单元格对齐方式为顶端对齐 */
table{
border-collapse: collapse;
border: none;
}
td, th{
border: solid #000 1px;
}
.output { font-weight: bold; } /* 计算结果定义为粗体 */
.btn{
font-weight: 700;
line-height: 30px;
width: 100px;
height: 35px;
}
.help
{
float:right;
cursor:pointer;
line-height: 10px;
margin-top: -4px;
margin-right: -4px;
}
.nr {
color: #666;
font-size: 12px;
padding: 10px 0 5px
}
.tsk {
background: #f8f8f8;
border: 1px solid #CCC;
box-shadow: 0 1px 5px #DDD;
line-height: 20px;
padding: 10px;
position: absolute;
display: none;
z-index: 10000
} .circle {
width: 15px;
height: 15px;
font-weight: 700;
text-indent:4px; cursor:pointer;
float:left;
line-height:16px;
background: #5A8BDC;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
}
</style> <script>
function $(id){ return document.getElementById(id); }
function helpClick(obj)
{
$(obj.id+"_help").style.display = "block";
} function hidHelp()
{
$("debxhk_help").style.display = "none";
$("debjhk_help").style.display = "none";
} </script> </head>
<body> <table>
<tbody>
<tr>
<th colspan=2>输入数据:</th>
</tr>
<tr>
<td width=100px>
<!--Amount of the loan-->贷款总额:</td>
<td><input id="amount" value="500000" /><span style="margin-left:-18px">元</span></td>
</tr>
<tr>
<td>
<!--Annual interest-->年利息:</td>
<td><input id="apr" value="5.65" /><span style="margin-left:-14px">%</span></td>
</tr>
<td>
利率折扣:</td>
<td>
<select id=llzk style="width:156px;">
<option value="0.7" >最新基准利率7折</option>
<option value="0.8" >最新基准利率8折</option>
<option value="0.83">最新基准利率8.3折</option>
<option value="0.85">最新基准利率8.5折</option>
<option value="0.88">最新基准利率8.8折</option>
<option value="0.9" >最新基准利率9折</option>
<option value="0.95">最新基准利率9.5折</option>
<option value="1.0" selected=true>最新基准利率</option>
<option value="1.05">最新基准利率1.05倍</option>
<option value="1.1" >最新基准利率1.1倍</option>
<option value="1.2" >最新基准利率1.2倍</option>
<option value="1.3" >最新基准利率1.3倍</option>
</select>
</td>
</tr>
<tr>
<td>
<!--Repayment period (years)-->偿还期限:</td>
<td><input id="years" value="30" /><span style="margin-left:-18px">年</span></td>
</tr>
<tr style="display:none">
<td>
<!--Zipcode (to find lenders)-->邮政编码(查找放贷人):</td>
<td><input id="zipcode" /></td>
</tr>
<tr>
<th colspan=2>
<input class="btn" type=button onclick="calculate();" value="计 算" />&nbsp;&nbsp;&nbsp;
<input class="btn" type=reset value="重 置" />
</th>
</tr>
<tr>
<th colspan=2>
<!--Approximate Payments-->输出结果:</th>
</tr>
<tr>
<td>
<!--Monthly payment-->每月付款:</td>
<td><span class="output" id="payment">0</span></td>
</tr>
<tr>
<td>
<!--Total payment-->付款总额:</td>
<td><span class="output" id="total">0</span></td>
</tr>
<tr>
<td>
<!--Total interest-->利息总额:</td>
<td><span class="output" id="totalinterest">0</span></td>
</tr>
<tr>
<td colspan=2>图表:贷款金额,累计金额,利息支付</td>
</tr>
<tr>
<td colspan="2">
<canvas id="graph" width="500" height="250"></canvas>
</td>
</tr>
<tr>
<td colspan="2">
<table id="result" style="width:100%">
<tbody>
<tr>
<td style="position:relative;width:50%;">
<div>
<span style="float:left">每月等额还款</span>
<div class="circle" onclick=helpClick(this) id="debxhk">?</div>
</div>
<div class="tsk" id="debxhk_help" style="width:214px;left:1px;top:16px">
<div onclick="hidHelp()" class="help">&nbsp;x</div>
<div class="nr">
每月等额还款即等额本息还款法,指借款人每月按相等的金额偿还贷款本息,其中每月贷款利息按月初剩余贷款本金计算并逐月结清。
</div>
</div>
<table style="clear:both" cellpadding="0" cellspacing="0" class="tbl" >
<tbody>
<tr>
<td class="td1" width=100px>贷款总额</td>
<td class="td2"><var id="_debx_dkje">0</var> 元</td>
</tr>
<tr>
<td class="td1">还款月数</td>
<td class="td2"><var id="_debx_dkqx">0</var> 月</td>
</tr>
<tr>
<td class="td1">首月还款</td>
<td class="td2"><em id="_debx_myhk">0</em> 元</td>
</tr>
<tr>
<td class="td1">每月递减</td>
<td class="td1"><em id="_debj_mydj">0</em> 元</td>
</tr>
<tr>
<td class="td1">总支付利息</td>
<td class="td2"><em id="_debx_zflx">0</em> 元</td>
</tr>
<tr>
<td class="td1">本息合计</td>
<td class="td2"><em id="_debx_hkze">1,039,024.42</em> 元</td>
</tr>
</tbody>
</table>
</td>
<td style="position:relative">
<div>
<span style="float:left">逐月递减还款</span>
<div onclick=helpClick(this) class="circle" id="debjhk">?</div>
</div>
<div class="tsk" id="debjhk_help" style="width:214px;left:1px;top:16px">
<div onclick="hidHelp()" class="help">&nbsp;X</div>
<div class="nr">
逐月递减还款即等额本金还款法,指本金保持相同,利息逐月递减,月还款数递减;由于每月的还款本金额固定,而利息越来越少,贷款人起初还款压力较大,但是随时间的推移每月还款数也越来越少。
</div>
</div>
<table style="clear:both" cellpadding="0" cellspacing="0" class="tbl">
<tbody>
<tr>
<td class="td1" width=100px>贷款总额</td>
<td class="td2"><var id="_debj_dkje">0</var> 元</td>
</tr>
<tr>
<td class="td1">还款月数</td>
<td class="td2"><var id="_debj_dkqx">0</var> 月</td>
</tr>
<tr>
<td class="td1">首月还款</td>
<td class="td2"><em id="_debj_syhk">0</em> 元
</td>
</tr>
<tr>
<td class="td1">每月递减</td>
<td class="td1"><em id="_debj_mydj">0</em> 元</td>
</tr>
<tr>
<td class="td1">总支付利息</td>
<td class="td2"><em id="_debj_zflx">0</em> 元</td>
</tr>
<tr>
<td class="td1">本息合计</td>
<td class="td2"><em id="_debj_hkze">1,039,024.42</em> 元</td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td height="25" colspan="2">
<span class="result-info">此结果仅供参考,实际应缴费以当地为准</span>
</td>
</tr>
</tbody>
</table>
</td>
</tr> </tbody>
</table> <script>
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"); // 假设所有的输入都是合法的,将从input元素中获取输入数据
// 将百分比格式转换为小数格式,并从年利率转换为月利率
// 将年度赔付转换为月度赔付
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); // Math.pow()进行幂次运算
var monthly = (principal*x*interest)/(x-1); // 如果结果没有超过JavaScript能表示的数字范围,且用户的输入也正确
// 这里所展示的结果就是合法的
if (isFinite(monthly)) {
// 将数据填充至输出字段的位置,四舍五入到小数点后两位数字
payment.innerHTML = monthly.toFixed(2);
total.innerHTML = (monthly * payments).toFixed(2);
totalinterest.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 = ""
totalinterest.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>";
} // 将数据在HTML元素中呈现出来
ad.innerHTML = "<ul>" + list + "</ul>";
}
}
} // 在HTML<canvas>元素中用图表展示月度贷款余额、利息和资产收益
// 如果不传入参数的话,则清空之前的图表数据
function chart(principal, 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, 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 = "chartreuse"; // 使用绿色绘制图形
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("Year", x, y-5); // 在坐标轴做标记
if (year % 5 == 0 && year*12 !== payments) // 每5年的数据
g.fillText(String(year), x, y-5);
} // 将赔付数额标记在右边界
g.textAlign = "right"; // 文字右对齐
g.textBaseline = "middle"; // 文字垂直居中
var ticks = [monthly*payments, principal]; // 我们将要用到的两个点
var rightEdge = paymentToX(payments); // 设置X坐标
for(var 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);
}
}
</script>
</body>
</html>

版本二:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=gb2312">
<meta charset="utf-8"/>
<title>JS计算器,贷款利率计算器</title>
<!--参考出处:http://www.codefans.net/jscss/code/3613.shtml--> <style> /* 这是一个CSS样式表:定义了程序输出的样式 */
body{ font-size:12px;}
#payment { } /* 定义 id="payment" 的元素样式 */
#graph { border: solid black 1px; } /* 图表有一个1像素的边框 */
th, td {vertical-align: top; } /* 表格单元格对齐方式为顶端对齐 */
table{
border-collapse: collapse;
border: none;
}
td, th{
border: solid #000 1px;
}
.output { font-weight: bold; } /* 计算结果定义为粗体 */
.btn{
font-weight: 700;
line-height: 30px;
width: 100px;
height: 35px;
}
.tbl{
width:95%;
}
.td1{
width:70px
}
.td2{
width:140px
}
.help
{
float:right;
cursor:pointer;
line-height: 10px;
margin-top: -6px;
margin-right: -6px;
}
.nr {
color: #666;
font-size: 12px; padding-top:0px;
margin: 8px -2px -2px;
}
.tsk {
background: #f8f8f8;
border: 1px solid #CCC;
box-shadow: 0 1px 5px #DDD;
line-height: 20px;
padding: 10px;
position: absolute;
display: none;
z-index: 10000;
width:215px;
left:1px;
top:16px
} .circle {
width: 15px;
height: 15px;
font-weight: 700;
text-indent:4px; cursor:pointer;
float:left;
line-height:16px;
background: #5A8BDC;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
}
.resultInfo{
font-weight:normal;
font-size:10px;
color:red;
} </style> <script>
function $(id){ return document.getElementById(id); }
function helpClick(obj)
{
$(obj.id+"_help").style.display = "block";
} function hidHelp(obj)
{
obj.parentElement.style.display = "none";
} </script> </head>
<body> <table width=500px>
<tbody>
<tr>
<th colspan=2 style="text-align:left;font-size:24px;background-color:#3f3">输入数据:</th>
</tr>
<tr>
<td width=100px>
<!--Amount of the loan-->贷款总金额:</td>
<td><input id="amount" value="500000" /><span style="margin-left:-18px">元</span></td>
</tr>
<tr>
<td>
<!--Annual interest-->基准年利率:</td>
<td><input id="apr" value="3.5" /><span style="margin-left:-14px">%</span></td>
</tr>
<td>
利率折扣:</td>
<td>
<select id=llzk style="width:173px;">
<option value="2.0" >基准利率2倍</option>
<option value="1.5" >基准利率1.5倍</option>
<option value="1.4" >基准利率1.4倍</option>
<option value="1.3" >基准利率1.3倍</option>
<option value="1.2" >基准利率1.2倍</option>
<option value="1.1" >基准利率1.1倍</option>
<option value="1.05">基准利率1.05倍</option>
<option value="1.0" selected=true>基准利率</option>
<option value="0.95">基准利率9.5折</option>
<option value="0.9" >基准利率9折</option>
<option value="0.88">基准利率8.8折</option>
<option value="0.85">基准利率8.5折</option>
<option value="0.83">基准利率8.3折</option>
<option value="0.8" >基准利率8折</option>
<option value="0.75" >基准利率7.5折</option>
<option value="0.7" >基准利率7折</option>
</select>
</td>
</tr>
<tr>
<td>
<!--Repayment period (years)-->贷款期限:</td>
<td><input id="years" value="30" /><span style="margin-left:-18px">年</span></td>
</tr>
<tr style="display:none">
<td>
<!--Zipcode (to find lenders)-->邮政编码(查找放贷人):</td>
<td><input id="zipcode" /></td>
</tr>
<tr>
<th colspan=2>
<input class="btn" type=button onclick="calculate();" value="计 算" />&nbsp;&nbsp;
<input class="btn" type=button onclick="RevCalculate();" value="反 推" />&nbsp;&nbsp;
<input class="btn" type=reset value="重 置" />
</th>
</tr>
<tr>
<th colspan=2 style="text-align:left;font-size:24px;background-color:#3f3">
<!--Approximate Payments-->输出结果:<span class="resultInfo">此结果仅供参考,实际应缴费以当地为准</span>
</th>
</tr>
<tr>
<td>
<!--Monthly payment-->每月付款:</td>
<td>
<input id="payment" value="30" />
</td>
</tr>
<tr>
<td>
<!--Total payment-->付款总额:</td>
<td><span class="output" id="total">0</span></td>
</tr>
<tr>
<td>
<!--Total interest-->利息总额:</td>
<td><span class="output" id="totalinterest">0</span></td>
</tr>
<tr>
<td colspan="2">
<table id="result" style="width:100%">
<tbody>
<tr>
<td style="position:relative;width:50%;">
<div>
<span style="float:left">每月等额还款</span>
<div class="circle" onclick="helpClick(this)" id="debxhk">?</div>
</div>
<div class="tsk" id="debxhk_help">
<div onclick="hidHelp(this)" class="help">&nbsp;X</div>
<div class="nr">
每月等额还款即等额本息还款法,指借款人每月按相等的金额偿还贷款本息,其中每月贷款利息按月初剩余贷款本金计算并逐月结清。
</div>
</div>
<table style="clear:both" cellpadding="0" cellspacing="0" class="tbl">
<tbody>
<tr>
<td class="td1">贷款总额</td>
<td class="td2"><var id="_debx_dkze">0</var> 元</td>
</tr>
<tr>
<td class="td1">还款月数</td>
<td class="td2"><var id="_debx_hkys">0</var> 月</td>
</tr>
<tr>
<td class="td1">首月还款</td>
<td class="td2"><em id="_debx_syhk">0</em> 元</td>
</tr>
<tr>
<td class="td1">每月递减</td>
<td class="td1"><em id="_debj_mydj">0</em> 元</td>
</tr>
<tr>
<td class="td1">总付利息</td>
<td class="td2"><em id="_debx_zflx">0</em> 元</td>
</tr>
<tr>
<td class="td1">本息合计</td>
<td class="td2"><em id="_debx_bxhj">1,039,024.42</em> 元</td>
</tr>
</tbody>
</table>
</td>
<td style="position:relative">
<div>
<span style="float:left">逐月递减还款</span>
<div onclick="helpClick(this)" class="circle" id="debjhk">?</div>
</div>
<div class="tsk" id="debjhk_help">
<div onclick="hidHelp(this)" class="help">&nbsp;X</div>
<div class="nr">
逐月递减还款即等额本金还款法,指本金保持相同,利息逐月递减,月还款数递减;由于每月的还款本金额固定,而利息越来越少,贷款人起初还款压力较大,但是随时间的推移每月还款数也越来越少。
</div>
</div>
<table style="clear:both" cellpadding="0" cellspacing="0" class="tbl">
<tbody>
<tr>
<td class="td1">贷款总额</td>
<td class="td2"><var id="_debj_dkze">0</var> 元</td>
</tr>
<tr>
<td class="td1">还款月数</td>
<td class="td2"><var id="_debj_hkys">0</var> 月</td>
</tr>
<tr>
<td class="td1">首月还款</td>
<td class="td2"><em id="_debj_syhk">0</em> 元
</td>
</tr>
<tr>
<td class="td1">每月递减</td>
<td class="td1"><em id="_debj_mydj">0</em> 元</td>
</tr>
<tr>
<td class="td1">总付利息</td>
<td class="td2"><em id="_debj_zflx">0</em> 元</td>
</tr>
<tr>
<td class="td1">本息合计</td>
<td class="td2"><em id="_debj_bxhj">1,039,024.42</em> 元</td>
</tr>
</tbody>
</table> </td>
</tr>
<tr style="display:none">
<td colspan="2">
<span class="resultInfo">此结果仅供参考,实际应缴费以当地为准</span>
</td>
</tr>
</tbody>
</table>
</td>
</tr> <tr>
<td colspan=2><span style="font-weight:bold;">图表:贷款金额,累计金额,利息支付</span></td>
</tr>
<tr>
<td colspan="2">
<canvas id="graph" width="500" height="250"><span style="font-weight:bold;color:red;">请在支持HTML5的浏览器中打开</span></canvas>
</td>
</tr>
</tbody>
</table> <script>
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");//贷款总利息 // 假设所有的输入都是合法的,将从input元素中获取输入数据
// 将百分比格式转换为小数格式,并从年利率转换为月利率
// 将年度赔付转换为月度赔付
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); // Math.pow()进行幂次运算
var monthly = (principal*x*interest)/(x-1); // 如果结果没有超过JavaScript能表示的数字范围,且用户的输入也正确
// 这里所展示的结果就是合法的
if (isFinite(monthly)) {
// 将数据填充至输出字段的位置,四舍五入到小数点后两位数字
//payment.innerHTML = monthly.toFixed(2);
payment.value=monthly.toFixed(2);
total.innerHTML = (monthly * payments).toFixed(2);
totalinterest.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 = ""
totalinterest.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>";
} // 将数据在HTML元素中呈现出来
ad.innerHTML = "<ul>" + list + "</ul>";
}
}
} // 在HTML<canvas>元素中用图表展示月度贷款余额、利息和资产收益
// 如果不传入参数的话,则清空之前的图表数据
// principal:贷款金额
// interest:利息
// monthly:每月还款额
// payments:还款期限
function chart(principal, 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, 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("总支出", 90,15); // 将文字绘制到图例中 // 总贷款额的还款进度,很多资产数据并不是线性的,很难将其反映至图表中
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 = "#78E682"; // 使用绿色绘制图形
g.fill(); // 曲线之下的部分均填充
g.fillText("贷款数额", 90,30); // 文本颜色设置为绿色 // 余额,再次循环,余额数据显示为黑色粗线条
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 = 2; // 将直线宽度加粗
g.strokeStyle = "#E422CB"; // 绘制线条的颜色
g.stroke(); // 绘制余额的曲线
g.fillStyle = "#E422CB"; // 使用黑色字体
g.fillText("贷款余额", 90,45); // 图例文字 // 将年度数据在X轴做标记
g.fillStyle = "black"; // 使用黑色字体
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("1年", x, y-5); // 在坐标轴做标记
if (year % 5 == 0 && year*12 !== payments) // 每5年的数据
g.fillText(String(year)+"年", x, y-5);
} // 将赔付数额标记在右边界
g.textAlign = "right"; // 文字右对齐
g.textBaseline = "middle"; // 文字垂直居中
var ticks = [monthly*payments, principal]; // 我们将要用到的两个点
var rightEdge = paymentToX(payments); // 设置X坐标
for(var i = 0; i < ticks.length; i++) { // 对每两个点做循环
var y = amountToY(ticks[i]); // 计算每个标记的Y坐标
g.fillRect(rightEdge-3, y-0.5, 5,1); // 绘制标记
g.fillText(String(ticks[i].toFixed(0)),rightEdge-5, y); // 绘制文本
}
g.textAlign = "left";
g.fillRect(0, y-0.5, 6,1); // 绘制标记
g.fillText(String(principal),15, y); // 绘制文本
}
</script>
</body>
</html>

版本三:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=gb2312">
<meta charset="utf-8"/>
<title>JS计算器,贷款利率计算器</title>
<!--参考出处:http://www.codefans.net/jscss/code/3613.shtml--> <style> /* 这是一个CSS样式表:定义了程序输出的样式 */
body{ font-size:12px;}
#payment { } /* 定义 id="payment" 的元素样式 */
#graph { border: solid black 1px; } /* 图表有一个1像素的边框 */
th, td {vertical-align: top; } /* 表格单元格对齐方式为顶端对齐 */
table{
border-collapse: collapse;
border: none;
}
td, th{
border: solid #000 1px;
}
.output { font-weight: bold; } /* 计算结果定义为粗体 */
.btn{
font-weight: 700;
line-height: 30px;
width: 100px;
height: 35px;
}
.tbl{
width:95%;
}
.td1{
width:70px
}
.td2{
width:140px
}
.help
{
float:right;
cursor:pointer;
line-height: 10px;
margin-top: -6px;
margin-right: -6px;
}
.nr {
color: #666;
font-size: 12px; padding-top:0px;
margin: 8px -2px -2px;
}
.tsk {
background: #f8f8f8;
border: 1px solid #CCC;
box-shadow: 0 1px 5px #DDD;
line-height: 20px;
padding: 10px;
position: absolute;
display: none;
z-index: 10000;
width:215px;
left:1px;
top:16px
} .circle {
width: 15px;
height: 15px;
font-weight: 700;
text-indent:4px; cursor:pointer;
float:left;
line-height:16px;
background: #5A8BDC;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
}
.resultInfo{
font-weight:normal;
font-size:10px;
color:red;
} </style> <script language="JavaScript">
//格式化参数说明:
//y:年,M:月,d:日,k周,h:时,m分,s:秒,S毫秒
Date.prototype.Format = function(formatIn){
var formatOut=formatIn;
var o = {
"M+" : this.getMonth()+1, //month
"d+" : this.getDate(), //day
"h+" : this.getHours(), //hour
"m+" : this.getMinutes(), //minute
"s+" : this.getSeconds(), //second
"q+" : Math.floor((this.getMonth()+3)/3), //quarter
"k+" : Math.ceil((Math.ceil((this.valueOf()-new Date(this.getFullYear(),0,1).valueOf())/86400000)+((new Date(this.getFullYear(),0,1).getDay()+1)-1))/7) //weeks
}
if(/(y+)/ig.test(formatIn))
for(var i=0;i<(formatIn.match(/(y+)/ig)).length;i++){formatOut=formatOut.replace((formatIn.match(/(y+)/ig))[i],(this.getFullYear()+"").substr(4 - (formatIn.match(/(y+)/ig))[i].length));}
for(var k in o){
var reg=new RegExp("("+ k +")","g");
if(reg.test(formatIn))var t=formatIn.match(reg);
for(var i in t)formatOut=formatOut.replace(t[i],(o[k]+"").length==1?("0"+ o[k]).substr(t[i].length>2?-t[i].length:2-t[i].length):o[k]);
}
if(/(S+)/g.test(formatIn))
formatOut=formatOut.replace(formatIn.match(/(S+)/g)[0],(this.getMilliseconds()+"").length<2?("00"+this.getMilliseconds()).substr(0,formatIn.match(/(S+)/g)[0].length):((this.getMilliseconds()+"").length==2?("0"+this.getMilliseconds()).substr(0,formatIn.match(/(S+)/g)[0].length):(this.getMilliseconds()+"").substr(0,formatIn.match(/(S+)/g)[0].length)));
return formatOut;
}
//测试代码
var dt=new Date;
var f1="yyyy-MM-dd 第k周 hh:mm:ss.SS";
var f2="MM-dd kkk yy-M-d k h:m:s.S";
var f3="hh:mm:ss.SSSS";
//alert(dt.Format(f1));
//alert(dt.Format(f2)); ; function $(id){ return document.getElementById(id); }
function helpClick(obj)
{
$(obj.id+"_help").style.display = "block";
} function hidHelp(obj)
{
obj.parentElement.style.display = "none";
} function Test()
{
var t1=document.createElement("table");
t1.width="100%";
t1.insertRow();
t1.rows[0].innerHTML="<th width='10%'>期次</th><th>年月</th><th width='20%'>本金</th><th width='20%'>利息</th><th width='20%'>月供</th><th>剩余贷款</th>"; /*
t1.insertRow();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].cells[0].innerHTML = 1;
t1.rows[t1.rows.length-1].cells[1].innerHTML = 2;
t1.rows[t1.rows.length-1].cells[2].innerHTML = 3;
*/ //t1.rows[t1.rows.length-1].insertCell()
//tab.appendChild("<tr><td>1</td><td>2</td></tr>");
//tab.appendChild(t1); //alert(newRow.cells.length);
//div.appendChild(table);
//cell.innerHTML = '';
//StringBuilder html = new StringBuilder("<table width='100%'>");
//document.getElementById('zhutiTable').appendChild(t); // 查找文档中用于输入输出的元素
var amount = document.getElementById("amount");//贷款总额
var apr = document.getElementById("apr");//年利息
var years = document.getElementById("yearsToM");//偿还期限
var startYM = document.getElementById("startYM");//邮政编码(查找放贷人)
var payment = document.getElementById("payment");//月还贷款额
var total = document.getElementById("total");//还贷款总额
var totalinterest = document.getElementById("totalinterest");//贷款总利息 // 假设所有的输入都是合法的,将从input元素中获取输入数据
// 将百分比格式转换为小数格式,并从年利率转换为月利率
// 将年度赔付转换为月度赔付
var principal = parseFloat(amount.value);
var interest = parseFloat(apr.value) / 100 / 12;
var payments = parseFloat(years.value) * 12;
payments = years.value; // 现在计算月度赔付的数据
var x = Math.pow(1 + interest, payments); // Math.pow()进行幂次运算
var monthly = (principal*x*interest)/(x-1); //月还款额=贷款金额*年利率/12*(1+年利率/12)^(年期*12)/((1+年利率/12)^(年期*12)-1)
var yue = principal*(interest)*x/(Math.pow(1+interest,payments)-1);
var shy = principal;
var dtt = new Date(startYM.value.split("-")[0],startYM.value.split("-")[1]-1,1) for(i=0;i<payments;i++){
//第N月本金: 月还款额=(1+年利率/12)^(N-1-年期*12)
var y_bj=Math.pow(interest+1,i-payments)
//第N月利息: 月还款额=(1-(1+年利率/12)^(N-1-年期*12))
var y_lx=1-Math.pow(1+interest,i-payments);
t1.insertRow(t1.rows.length);
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].insertCell();
t1.rows[t1.rows.length-1].cells[0].innerHTML = i+1;
t1.rows[t1.rows.length-1].cells[1].innerHTML = dtt.Format("yyyy-MM");
t1.rows[t1.rows.length-1].cells[2].innerHTML = (monthly*y_bj).toFixed(2);
t1.rows[t1.rows.length-1].cells[3].innerHTML = (monthly*y_lx).toFixed(2);
t1.rows[t1.rows.length-1].cells[4].innerHTML = monthly.toFixed(2);
t1.rows[t1.rows.length-1].cells[5].innerHTML = (principal-=(monthly*y_bj)).toFixed(2); dtt = dtt.setMonth(dtt.getMonth()+1);
dtt = new Date(dtt);
} var tr=$("tr_tab");
tr.cells[0].innerHTML=t1.outerHTML; } </script> </head>
<body> <table id="t_main" width=500px>
<tbody>
<tr>
<th colspan=2 style="text-align:left;font-size:24px;background-color:#3f3">输入数据:</th>
</tr>
<tr>
<td width=100px>
<!--Amount of the loan-->贷款总金额:</td>
<td><input id="amount" value="500000" /><span style="margin-left:-18px">元</span></td>
</tr>
<tr>
<td>
<!--Annual interest-->基准年利率:</td>
<td><input id="apr" value="3.5" /><span style="margin-left:-14px">%</span></td>
</tr>
<td>
利率折扣:</td>
<td>
<select id=llzk style="width:173px;">
<option value="2.0" >基准利率2倍</option>
<option value="1.5" >基准利率1.5倍</option>
<option value="1.4" >基准利率1.4倍</option>
<option value="1.3" >基准利率1.3倍</option>
<option value="1.2" >基准利率1.2倍</option>
<option value="1.1" >基准利率1.1倍</option>
<option value="1.05">基准利率1.05倍</option>
<option value="1.0" selected=true>基准利率</option>
<option value="0.95">基准利率9.5折</option>
<option value="0.9" >基准利率9折</option>
<option value="0.88">基准利率8.8折</option>
<option value="0.85">基准利率8.5折</option>
<option value="0.83">基准利率8.3折</option>
<option value="0.8" >基准利率8折</option>
<option value="0.75" >基准利率7.5折</option>
<option value="0.7" >基准利率7折</option>
</select>
</td>
</tr>
<tr>
<td>
<!--Repayment period (years)-->贷款期限:</td>
<td><input id="yearsToM" value="180" /><span style="margin-left:-18px">月</span></td>
</tr>
<tr>
<td>
<!--Zipcode (to find lenders)-->首次还贷年月:</td>
<td><input id="startYM" value='2016-01' />
<span id="lenders"></span>
</td>
</tr>
<tr>
<th colspan=2>
<input class="btn" type=button onclick="calculate();" value="计 算" />&nbsp;&nbsp;
<input class="btn" type=button onclick="Test();" value="测 试" />&nbsp;&nbsp;
<input class="btn" type=reset value="重 置" />
</th>
</tr>
<tr>
<th colspan=2 style="text-align:left;font-size:24px;background-color:#3f3">
<!--Approximate Payments-->输出结果:<span class="resultInfo">此结果仅供参考,实际应缴费以当地为准</span>
</th>
</tr>
<tr>
<td>
<!--Monthly payment-->每月付款:</td>
<td>
<input id="payment" value="30" />
</td>
</tr>
<tr>
<td>
<!--Total payment-->付款总额:</td>
<td><span class="output" id="total">0</span></td>
</tr>
<tr>
<td>
<!--Total interest-->利息总额:</td>
<td><span class="output" id="totalinterest">0</span></td>
</tr>
<tr>
<td colspan="2">
<table id="result" style="width:100%">
<tbody>
<tr>
<td style="position:relative;width:50%;">
<div>
<span style="float:left">每月等额还款</span>
<div class="circle" onclick="helpClick(this)" id="debxhk">?</div>
</div>
<div class="tsk" id="debxhk_help">
<div onclick="hidHelp(this)" class="help">&nbsp;X</div>
<div class="nr">
每月等额还款即等额本息还款法,指借款人每月按相等的金额偿还贷款本息,其中每月贷款利息按月初剩余贷款本金计算并逐月结清。
</div>
</div>
<table style="clear:both" cellpadding="0" cellspacing="0" class="tbl">
<tbody>
<tr>
<td class="td1">贷款总额</td>
<td class="td2"><var id="_debx_dkze">0</var> 元</td>
</tr>
<tr>
<td class="td1">还款月数</td>
<td class="td2"><var id="_debx_hkys">0</var> 月</td>
</tr>
<tr>
<td class="td1">首月还款</td>
<td class="td2"><em id="_debx_syhk">0</em> 元</td>
</tr>
<tr>
<td class="td1">每月递减</td>
<td class="td1"><em id="_debj_mydj">0</em> 元</td>
</tr>
<tr>
<td class="td1">总付利息</td>
<td class="td2"><em id="_debx_zflx">0</em> 元</td>
</tr>
<tr>
<td class="td1">本息合计</td>
<td class="td2"><em id="_debx_bxhj">1,039,024.42</em> 元</td>
</tr>
</tbody>
</table>
</td>
<td style="position:relative">
<div>
<span style="float:left">逐月递减还款</span>
<div onclick="helpClick(this)" class="circle" id="debjhk">?</div>
</div>
<div class="tsk" id="debjhk_help">
<div onclick="hidHelp(this)" class="help">&nbsp;X</div>
<div class="nr">
逐月递减还款即等额本金还款法,指本金保持相同,利息逐月递减,月还款数递减;由于每月的还款本金额固定,而利息越来越少,贷款人起初还款压力较大,但是随时间的推移每月还款数也越来越少。
</div>
</div>
<table style="clear:both" cellpadding="0" cellspacing="0" class="tbl">
<tbody>
<tr>
<td class="td1">贷款总额</td>
<td class="td2"><var id="_debj_dkze">0</var> 元</td>
</tr>
<tr>
<td class="td1">还款月数</td>
<td class="td2"><var id="_debj_hkys">0</var> 月</td>
</tr>
<tr>
<td class="td1">首月还款</td>
<td class="td2"><em id="_debj_syhk">0</em> 元
</td>
</tr>
<tr>
<td class="td1">每月递减</td>
<td class="td1"><em id="_debj_mydj">0</em> 元</td>
</tr>
<tr>
<td class="td1">总付利息</td>
<td class="td2"><em id="_debj_zflx">0</em> 元</td>
</tr>
<tr>
<td class="td1">本息合计</td>
<td class="td2"><em id="_debj_bxhj">1,039,024.42</em> 元</td>
</tr>
</tbody>
</table> </td>
</tr>
<tr style="display:none">
<td colspan="2">
<span class="resultInfo">此结果仅供参考,实际应缴费以当地为准</span>
</td>
</tr>
</tbody>
</table>
</td>
</tr> <tr>
<td colspan=2><span style="font-weight:bold;">图表:贷款金额,累计金额,利息支付</span></td>
</tr>
<tr>
<td colspan="2">
<canvas id="graph" width="500" height="250"></canvas>
</td>
</tr>
<tr id="tr_tab">
<td colspan="2">
</td>
</tr>
</tbody>
</table>
<div id="list"></div> <script>
function calculate() { //生成每月还款额表格
Test(); // 查找文档中用于输入输出的元素
var amount = document.getElementById("amount");//贷款总额
var apr = document.getElementById("apr");//年利息
var years = document.getElementById("yearsToM");//偿还期限
var startYM = document.getElementById("startYM");//邮政编码(查找放贷人)
var payment = document.getElementById("payment");//月还贷款额
var total = document.getElementById("total");//还贷款总额
var totalinterest = document.getElementById("totalinterest");//贷款总利息 // 假设所有的输入都是合法的,将从input元素中获取输入数据
// 将百分比格式转换为小数格式,并从年利率转换为月利率
// 将年度赔付转换为月度赔付
var principal = parseFloat(amount.value);
var interest = parseFloat(apr.value) / 100 / 12;
var payments = parseFloat(years.value) * 12;
payments = years.value; // 现在计算月度赔付的数据
var x = Math.pow(1 + interest, payments); // Math.pow()进行幂次运算
var monthly = (principal*x*interest)/(x-1); //月还款额=贷款金额*年利率/12*(1+年利率/12)^(年期*12)/((1+年利率/12)^(年期*12)-1)
var yue = principal*(interest)*x/(Math.pow(1+interest,payments)-1)
//第N月本金: 月还款额=(1+年利率/12)^(N-1-年期*12)
var y_bj=Math.pow(interest+1,-payments)
//第N月利息: 月还款额=(1-(1+年利率/12)^(N-1-年期*12))
var y_lx=1-Math.pow(1+interest,-payments) // 如果结果没有超过JavaScript能表示的数字范围,且用户的输入也正确
// 这里所展示的结果就是合法的
if (isFinite(monthly)) {
// 将数据填充至输出字段的位置,四舍五入到小数点后两位数字
//payment.innerHTML = monthly.toFixed(2);
payment.value=monthly.toFixed(2);
total.innerHTML = (monthly * payments).toFixed(2);
totalinterest.innerHTML = ((monthly*payments)-principal).toFixed(2); // 将用户的输入数据保存下来,这样在下次访问时也能取到数据
save(amount.value, apr.value, years.value, startYM.value); // 找到并展示本地放贷人,但忽略网络错误
try { // 捕获这段代码抛出的所有异常
//getLenders(amount.value, apr.value, years.value, startYM.value);
}
catch(e) { /* 忽略这些异常 */ } // 最后,用图表展示贷款余额、利息和资产收益
chart(principal, interest, monthly, payments);
}
else {
// 计算结果不是数字或者是无穷大,意味着输入数据是非法或不完整的
// 清空之前的输出数据
payment.innerHTML = ""; // 清空元素的文本内容
total.innerHTML = ""
totalinterest.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("yearsToM").value = localStorage.loan_years;
document.getElementById("startYM").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>";
} // 将数据在HTML元素中呈现出来
ad.innerHTML = "<ul>" + list + "</ul>";
}
}
} // 在HTML<canvas>元素中用图表展示月度贷款余额、利息和资产收益
// 如果不传入参数的话,则清空之前的图表数据
// principal:贷款金额
// interest:利息
// monthly:每月还款额
// payments:还款期限
function chart(principal, 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, 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("总支出", 15,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 = "#78E682"; // 使用绿色绘制图形
g.fill(); // 曲线之下的部分均填充
g.fillText("贷款数额", 60,20); // 文本颜色设置为绿色 // 余额,再次循环,余额数据显示为黑色粗线条
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 = 2; // 将直线宽度加粗
g.strokeStyle = "#e2e"; // 绘制线条的颜色
g.stroke(); // 绘制余额的曲线
g.fillStyle = "#e2e"; // 使用黑色字体
g.fillText("贷款余额", 120,20); // 图例文字 // 将年度数据在X轴做标记
g.fillStyle = "black"; // 使用黑色字体
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("1年", x, y-5); // 在坐标轴做标记
if (year % 5 == 0 && year*12 !== payments) // 每5年的数据
g.fillText(String(year)+"年", x, y-5);
} // 将赔付数额标记在右边界
g.textAlign = "right"; // 文字右对齐
g.textBaseline = "middle"; // 文字垂直居中
var ticks = [monthly*payments, principal]; // 我们将要用到的两个点
var rightEdge = paymentToX(payments); // 设置X坐标
for(var i = 0; i < ticks.length; i++) { // 对每两个点做循环
var y = amountToY(ticks[i]); // 计算每个标记的Y坐标
g.fillRect(rightEdge-3, y-0.5, 5,1); // 绘制标记
g.fillText(String(ticks[i].toFixed(0)),rightEdge-5, y); // 绘制文本
}
g.textAlign = "left";
g.fillRect(0, y-0.5, 6,1); // 绘制标记
g.fillText(String(principal),15, y); // 绘制文本
} </script> </body>
</html>

出处参考:

http://www.codefans.net/jscss/code/3613.shtml

http://www.rong360.com/calculator/fangdai.html

纯JS实现房贷利率报表对比的更多相关文章

  1. 纯JS实现俄罗斯方块,打造属于你的游戏帝国

    纯JS俄罗斯方块,打造属于你的游戏帝国. 本文原始作者博客 http://www.cnblogs.com/toutou 俄罗斯方块(Tetris, 俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏 ...

  2. F2工作流引擎之-纯JS Web在线可拖拽的流程设计器(八)

          Web纯JS流程设计器无需编程,完全是通过鼠标拖.拉.拽的方式来完成,支持串行.并行.分支.异或分支.M取N路分支.会签.聚合.多重聚合.退回.传阅.转交,都可以非常方便快捷地实现,管理员 ...

  3. [原创]纯JS实现网页中多选复选框checkbox和单选radio的美化效果

    图片素材: 最终效果图: <html><title> 纯JS实现网页中多选复选框checkbox和单选radio的美化效果</title><head>& ...

  4. 纯js异步无刷新请求(只支持IE)

    纯js异步无刷新请求 下载地址:http://pan.baidu.com/s/1slakL1F 所以因为非IE浏览器都禁止跨域请求,所以以只支持IE. <HTML> <!-- 乱码( ...

  5. [分享黑科技]纯js突破localstorage存储上线,远程抓取图片,并转码base64保存本地,最终实现整个网站所有静态资源离线到用户手机效果却不依赖浏览器的缓存机制,单页应用最新黑科技

    好久没有写博客了,想到2年前答应要放出源代码的也没放出来,最近终于有空先把纯js实现无限空间大小的本地存储的功能开源了,项目地址https://github.com/xueduany/localsto ...

  6. 纯js实现复制到剪贴板功能

    在网页上复制文本到剪切板,一般是使用JS+Flash结合的方法,网上有很多相关文章介绍.随着 HTML5 技术的发展,Flash 已经在很多场合不适用了,甚至被屏蔽.本文介绍的一款JS插件,实现了纯J ...

  7. baguetteBox.js响应式画廊插件(纯JS)

    baguetteBox.js baguetteBox.js 是一个简单和易于使用lightbox纯JavaScript脚本,拥有图像放大缩小并带有相应的CSS3过度,并能在触摸屏等设备上完美展示. D ...

  8. 纯js和纯css+html制作的手风琴的效果

    一:纯css+html的手风琴效果 这种用css写的手风琴比较简单,主要是应用到css中的,transition属性. 代码如下: <!DOCTYPE HTML> <html> ...

  9. 纯JS文本在线HTML编辑器KindEditor

    KindEditor(http://www.kindsoft.net)是一款比较专业,主流,好用的在线HTML编辑器. 它除了可以将文本进行编辑.将Word中的内容复制进来外,本身还可以拖动缩放(右下 ...

随机推荐

  1. Java底层代码实现多文件读取和写入

    需求: "E:/data/"目录下有四个文件夹,如下: 每个文件夹下有几个.csv文件,如下: 将每个文件夹下的.csv文件合并成一个以该文件夹命名的.csv文件. 做法: 找到& ...

  2. third application :Directions widget

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  3. PHP 最大化资源配置 Resource Limits 错误两则

    报错信息1:PHP Fatal error: Allowed memory size of 25165824 bytes exhausted (tried to allocate 67108888 b ...

  4. Javascript中一些常用的宽与高

    在使用javascript制作一些网络特效时,往往要根据显示网页的显示器的一些参数展开进行.所以一些关于显示器的参数如何得到显得十分重要.下面是一些常用的显示器参数,不妨好好记一下吧! 网页可见区域宽 ...

  5. firefox和chrome实现页面打印自动分页

    在Firefox和chrome中直接调用打印功能的js方法是 window.print(); 但是如果页面很长,那么就需要分页,这时只需要在页面中添加css属性即可,如果想自动分页,则如下所示 < ...

  6. java深入探究11-基础加强

    1. ? extends String:String 子类;? super String:String 父类 2.反射->参数化类型表示 ParameteredType:参数化类型表示,就是获得 ...

  7. DataX的安装

    DataX的安装 1. 可下载tar包 https://github.com/alibaba/DataX/blob/master/userGuid.md 2. 下载源码自己编译 git clone h ...

  8. keystone uwsgi failed

    ~$ /usr/local/bin/uwsgi /etc/keystone/keystone-uwsgi-public.ini[uWSGI] getting INI configuration fro ...

  9. Android国际化-图片国际化和文本字符国际化

    注意: 1.是在res目录下面,新建文件夹 2.需要国际化的文本资源和图片资源名称是一样的 图片国际化 默认:drawable-xhdpi 中文简体:drawable-zh-rCN-xhdpi(或者不 ...

  10. ie 元素兼容性总结

    css 属性元素 2.z-index 正常按自身层级决定显示顺序,在ie6 7 还需要依赖于父级的层级决定,排布在后边的元素排在前面.后来者居上覆盖前者. IE6,7支持inline元素转换成inli ...