废话不多说上例子代码:

1 <!DOCTYPE html>
2 <html>
3
4 <head>
5 <meta charset="UTF-8">
6 <title>JavaScript Loan Calculator</title>
7 <style>
8 .output{font-weight: bold;}
9 #payment{text-decoration: underline;}
10 #graph{border: 1px solid black;}
11 th, td{vertical-align: top;}
12
13 </style>
14 </head>
15
16 <body>
17 <table>
18 <tr>
19 <th>Enter Loan Data:</th>
20 <td></td>
21 <th>Loan Balance,Cumulative Equity,and Interest Payments</th>
22 </tr>
23 <tr>
24 <td>Amount of the loan($):</td>
25 <td><input id="amount" οnchange="calculate();"/></td>
26 <!--数量-->
27 <td rowspan="8"><canvas id="graph" width="400" height="250"></canvas></td>
28 <!--图表-->
29 </tr>
30 <tr>
31 <td>Annual interest(%):</td>
32 <td><input id="apr" οnchange="calculate();" /></td>
33 <!--年百分利率-->
34 </tr>
35 <tr>
36 <td>Repayment period (years):</td>
37 <td><input id="years" οnchange="calculate();" /></td>
38 </tr>
39 <tr>
40 <td>Zipcode (to find lenders):</td>
41 <td><input id="zipcode" οnchange="calculate();" /></td>
42 <!--邮政编码-->
43 </tr>
44 <tr>
45 <td>Approximate Payments:</td>
46 <td><button id="years" onclick="calculate();">Calculate</button></td>
47 <!--计算-->
48 </tr>
49 <tr>
50 <td>Monthly payment:</td>
51 <td>$<span class="output" id="payment"></span></td>
52 <!--付款-->
53 </tr>
54 <tr>
55 <td>Total interest:</td>
56 <td>$<span class="output" id="total"></span></td>
57 <!--全部的-->
58 </tr>
59 <tr>
60 <td>Total payment:</td>
61 <td>$<span class="output" id="totalinterest"></span></td>
62 <!--总利息-->
63 </tr>
64 <tr>
65 <th>Spinsors:</th>
66 <td colspan="2">
67 Apply for your loan with one of these fine lenders:
68 <div id="lenders"></div>
69 <!--贷款人-->
70 </td>
71 </tr>
72 </table>
73 <script>
74 //"use strict";
75 function calculate(){
76 //查找文档中用于输入输出的元素
77 var amount = document.getElementById("amount");
78 var apr = document.getElementById("apr");
79 var years = document.getElementById("years");
80 var zipcode = document.getElementById("zipcode");
81 var payment = document.getElementById("payment");
82 var total = document.getElementById("total");
83 var totalinterest = document.getElementById("totalinterest");
84
85 //假如所有的输入都是合法的,将从input中获取输入数据
86 //将百分比格式转换成小数格式,并从年利率转化成月利率
87 //将年度赔付装换成月度赔付
88 var principal = parseFloat(amount.value);
89 var interest = parseFloat(apr.value)/100/12;
90 var payments = parseFloat(years.value)*12;
91
92 //现在计算月度赔付的数据
93 var x =Math.pow(1+interest,payments);//Math.pow()进行幂次运算
94 var monthly = (principal*x*interest)/(x-1);
95
96 //如果结果没有超过js能表示的数字范围,且用户的输入也正确
97 //这里所展示的结果就是合法的
98 if(isFinite(monthly)){
99 //将数字填充到输出字段的位置,四舍五入到小数点后两位数字
100 payment.innerHTML = monthly.toFixed(2);
101 total.innerHTML = ((monthly*payments)-principal).toFixed(2);
102 totalinterest.innerHTML=((monthly*payments)-principal).toFixed(2);
103
104 //将用户输入的数据保存下来,这样下次访问时候也能取到数据
105 save(amount.value,apr.value,years.value,zipcode.value);
106
107 //找到并展示放贷人,但忽略网络错误
108 try{
109 //捕获这段代码抛出的所有异常
110 getLenders(amount.value,apr.value,years.value,zipcode.value);
111 }
112 //忽略这些异常
113 catch(e){}
114
115 //最后,用图表展示贷款余额,利息和资产收益
116 chart(principal,interest,monthly,payments);
117 }else{
118 payment.innerHTML="";
119 total.innerHTML="";
120 totalinterest.innerHTML="";
121 chart();
122 }
123 }
124
125 function save(amount,apr,years,zipcode){
126 if(window.localStorage){//只有在浏览器支持的时候才支持这里的代码
127 localStorage.loan_amount = amount;
128 localStorage.loan_apr = apr;
129 localStorage.loan_years = years;
130 localStorage.loan_zipcode = zipcode;
131 }
132 }
133
134 //文档首次加载的时候,将会尝试还原输入字段
135 window.οnlοad=function(){
136 //如果浏览器支持本地存储并且上次保存的值是存在的
137 if(window.localStorage && localStorage.loan_amount){
138 document.getElementById("amount").value = localStorage.loan_amount;
139 document.getElementById("apr").value = localStorage.loan_apr;
140 document.getElementById("years").value = localStorage.loan_years;
141 document.getElementById("zipcode").value = localStorage.loan_zipcode;
142 }
143 }
144
145 //将用户的输入发送到服务器端脚本返回一个本地放贷人的连接列表,在这个例子中并没有是现在这种查找放贷人的服务
146 //但如果该服务存在,该函数会使用它
147 function getLenders(amount,apr,years,zipcode){
148 //如果浏览器不支持XMLHttpRequest对象,则退出
149 if (!window.XMLHttpRequest)return;
150
151 //找到要显示放贷人列表的元素
152 var ad=document.getElementById("lenders");
153 if(!ad)return;//如果返回为空则退出
154
155 //将用户的输入数据进行url编码,并作为查询参数附加在URL里
156 var url = "getLenders.php"+
157 "?amt" + encodeURLComponent(amount)+
158 "?apr" + encodeURLComponent(apr)+
159 "?yrs" + encodeURLComponent(years)+
160 "?zip" + encodeURLComponent(zipcode);
161
162 //用XMLHttpRequest对象来提取返回数据
163 var req = new XMLHttpRequest();//发送一个新的请求
164 req.open("GET",url);//通过url发起一个http get请求
165 req.send(null);//不带任何正文发送这个请求
166
167 //在返回数据之前,注册一个事件处理函数,这个处理函数将会在服务器的的响应返回至客户端的时候调用
168 //这个异步边城模型在客户端js中是非常常见的
169 req.onreadystatechange = function(){
170 if(req.readyState == 4 && req.status == 200){
171 //如果代码运行到这里,说明我们得到了一个合法且完整的http响应
172 var response = req.responseText;//http响应是以字符串的形式呈现的
173 var lenders = JSON.parse(response);//将其解析为js数组
174
175 //将数组中的放贷人对象转换成HTML字符串的形式
176 var list="";
177 for(var i=0;i<lenders.length;i++){
178 list += "<li><a href='"+ lenders[i].url +"'>"+lenders[i].name+"</a></li>"
179 }
180
181 //将数据在HTML中呈现出来
182 ad.innerHTML = "<ul>"+list+"</ul>";
183 }
184 }
185
186 }
187
188 //在HTML<canvas>元素中用图表展示月度贷款余额,利息和资产情况
189 //如果不传参就清空之前的图表
190 function chart(principal,interest,monthly,payments){
191 var graph = document.getElementById("graph");
192 graph.width = graph.width;//用一种巧妙的手法清除并重置画布
193
194 //如果不传入参数,或者浏览器不支持画布,则直接返回。
195 if(arguments.length == 0 || !graph.getContext)return;
196
197 //获得画布元素『context』对象,这个对象定义了一组绘画API
198 var g = graph.getContext("2d");
199 var width = graph.width,height = graph.height;
200
201 //这里的函数的作用是将付款数字和美元数字转换成像素
202 function paymentToX(n){
203 return n*width/payments;
204 }
205 function amountToY(a){
206 return height - (a*height/(monthly*payments*1.05));
207 }
208
209 //付款数据是一条从(0,0)到(payments,monthly*payments)的直线
210 g.moveTo(paymentToX(0),amountToY(0));
211 g.lineTo(paymentToX(payments),amountToY(monthly*payments));
212 g.lineTo(paymentToX(payments),amountToY(0));
213 g.closePath();
214 g.fillStyle = "#f88";
215 g.fill();
216 g.font = "bold 12px sans-serif";
217 g.fillText("Total Interest Payments",20,20);
218
219 //很多资产数据并不是线性的,很难将其反映到图标中
220 var equity = 0;
221 g.beginPath();
222 g.moveTo(paymentToX(0),amountToY(0));
223 for(var p=1;p<=payments;p++){
224 //计算出每一笔赔付的利息
225 var thisMonthsINterest = (principal - equity)*interest;
226 equity += (monthly -thisMonthsInterest);
227 g.lineTo(paymentToX(p),amountToY(equity));
228 }
229 g.lineTo(paymentToX(payments),amountToY(0));
230 g.closePath();
231 g.fillStyle = "green";
232 g.fill();
233 g.fillText("Total Equity",20,35);
234
235 //再次循环,余额数据显示为黑色粗线条
236 var bal = principal;
237 g.beginPath();
238 g.moveTo(paymentToX(0),amountToY(bal));
239 for(var p=1;p<=payments;p++){
240 var thisMonthsInterest = bal*interest;
241 bal-=(monthly - thisMonthsInterest);
242 g.lineTo(paymentToX(p),amountToY(bal));
243 }
244
245 g.lineWidth = 3;
246 g.stroke();
247 g.fillStyle ="black";
248 g.fillText("Loan Balance",20,50);
249
250 //将年度数据在X轴做标记
251 g.textAlign = "center";
252 var y = amountToY(0);
253 for(var year = 1;year*12<=payments;year++){
254 var x=paymentToX(year*12);
255 g.fillRect(x-0.5,y-3,1,3);
256 if(year == 1) g.fillText("Year",x,y-5);
257 if(year %5 ==0 && year*12 !== payments)
258 g.fillText(String(year),x,y-5);
259 }
260
261 //将赔付数额标记在右边界
262 g.textAlign = "right";
263 g.textBaseline ="middle";
264 var ticks = [monthly * payments,principal];
265 var rightEdge = paymentToX(payments);
266 for(var i=0;i<ticks.length;i++){
267 var y = amountToY(ticks[i]);
268 g.fillRect(rightEdge-3,y-0.5,3,1);
269 g.fillText(String(ticks[i].toFixed(0)),rightEdge-5,y);
270 }
271 }
272 </script>
273 </body>
274
275 </html>
这边例子有个我感觉错误的地方:

1 <tr> 2 <td>Approximate Payments:</td> 3 <td><button id="years" onchange="calculate();">Calculate</button></td> 4 <!--计算--> 5 </tr>
这里的onchange是无法触发这个计算函数,需要改成onclick函数;

