微信小程序

房贷计算器

Posted by Tan Lin on February 19, 2019

目录结构-官方

用途 后缀 其他
逻辑文件 .js  
布局文件 .wxml  
配置文件 .json  
模块文件 .wxs 1.不可以引用其他js文件
2.可以使用Math等库

前言

由于2019/03/09 对代码进行了部分优化,包含按钮事件绑定等,请以文末的最新 Github 仓库代码为参考 以下部分有助于对项目框架的基本了解

环境准备

AppId 申请其实可以下载工具后,先使用测试AppId看看
开发工具下载下载后,直接打开新建工程就好

开始项目

打开微信开发者工具,(为了方便小程序预览,使用微信登录工具)

新建infoEntry页面 在index.wxml 里新添加一个button, < button bindtap=’tapToInfoEntry’> 进入贷款信息填写界面 </ button>

在事件处理函数添加点击事件的回调,注意function{}后面的, object中的成员分隔

  //事件处理函数
   bindViewTap: function() {
    wx.navigateTo({
       url: '../logs/logs'
    })
  },
  tapToInfoEntry: function() {
    wx.navigateTo({
      url: '../infoEntry/infoEntry'
    })
  },

infoEntry.js 文件移除其他暂不需要的额外方法,像这样

// pages/infoEntry/infoEntry.js
Page({
  /**
   * 页面的初始数据
   */
  data: {

  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },
})

目标要做成这个样子

信息填写页顶部及样式
// pages/infoEntry/infoEntry.js
  data: {
    loanType: 'providentFund', // commercial, combination
  },
  /** 点击事件,切换还款方式,等额本息/金 */
  changeLoan(event) {
    this.setData({
      loanType: event.currentTarget.id,
    });
  },
<!--pages/infoEntry/infoEntry.wxml-->
<wxs module="loan">
  var loanTypes = ['providentFund', 'commercial', 'combination'];
  module.exports = {
    types: loanTypes,
  }
</wxs>
<view class='liner-hor'>
  <view id="" bindtap='changeLoan' class='liner-hor-title-container'>
    <view class="sub-tab " hover-class='sub-tab-press'>公积金贷</view>
  </view>
  <view id="" bindtap='changeLoan' class='liner-hor-title-container'>
    <view class="sub-tab " hover-class='sub-tab-press'>商业贷</view>
  </view>
  <view id="" bindtap='changeLoan' class='liner-hor-title-container'>
    <view class="sub-tab " hover-class='sub-tab-press'>组合贷</view>
  </view>
</view>
<!-- top done -->
/* pages/infoEntry/infoEntry.wxss */
.liner-hor {
  height: 50px;
  display: flex;
  flex-direction: row;
}
.liner-hor .liner-hor-title-container {
  flex: 1;
  display: flex;
  background-color: #0dacac;
  align-items: center;
  justify-items: center;
}
.sub-tab {
  flex: 1;
  color: black;
  font-size: 16px;
  text-align: center;
}
.sub-tab.active {
  color: white;
}
.sub-tab-press {
  color: white;
}
信息填写页信息输入部分及样式
<!-- input area -->
<view class='desc-hor-container'>
  <block wx:if="">
    <view class='desc-hor'>
      <text class='title'>公积金贷款总额</text>
      <input bindinput="bindFundInput" placeholder="" class='money-input' type='digit' />
      <text class='title'></text>
    </view>
    <view>
      <view class='hor-line'/>
    </view>
  </block>

  <block wx:if="">
    <view class='desc-hor'>
      <text class='title'>商业贷款总额</text>
      <input bindinput="bindCommerInput" placeholder="" class='money-input' type='digit'></input>
      <text class='title'></text>
    </view>
    <view>
      <view class='hor-line'></view>
    </view>
  </block>
  <view class='desc-hor'>
    <text class='title'>贷款年限</text>
    <picker class='picker' mode='selector' bindchange="bindYearChange" range="" value="">
      <view class='picker-title'> </view>
    </picker>

  </view>
  <view>
    <view class='hor-line'></view>
  </view>

  <view wx:if="" class='desc-hor'>
    <text class='title'>年利率</text>
    <view class='calculator-container'>
      <view class='empty'></view>
      <input class='input' placeholder="" maxlength='5' type='digit'></input>
      <text class='text percentage'>%</text>
      <text class='text multiOp'>x</text>
      <input bindinput="fundMulity" class='input multiple' placeholder='1' maxlength='5' type='digit'></input>
      <text class='text'></text>
    </view>
    <text class='title endtext'> = %</text>
  </view>
  <!-- when combine loand -->
  <block wx:if="">
    <view class='desc-hor'>
      <text class='title'>年利率(商贷)</text>
      <view class='calculator-container'>
        <view class='empty'></view>
        <input class='input' placeholder="" maxlength='5' type='digit'></input>
        <text class='text percentage'>%</text>
        <text class='text multiOp'>x</text>
        <input bindinput="commerMulity" class='input multiple' placeholder='1' maxlength='5' type='digit'></input>
        <text class='text'> </text>
      </view>
      <text class='title endtext'> = %</text>
    </view>
  </block>
</view>
.desc-hor-container {
  display: flex;
  flex-direction: column;
  padding-left: 16px;
  padding-right: 16px;
}
.desc-hor-container .desc-hor {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  height: 100rpx;
}
.desc-hor-container .desc-hor.input {
  justify-content: space-around;
}
.title {
  font-size: 14px;
  text-align: center;
  color: #344d48;
}
.title.endtext {
  width: 65px;
  text-align: start;
  padding-left: 5px;
}
.desc-hor .money-input {
  margin-left: 50px;
  margin-right: 6px;
  font-size: 14px;
  text-align: right;
  color: #5c5f63;
  flex: 1;
}
.desc-hor .picker {
  flex: 1;
  margin-left: 50px;
}
.picker .picker-title {
  text-align: right;
  font-size: 14px;
  color: #344d48;
}
/* horizontal line */
.hor-line {
  margin: 0 auto;
  height: 1px;
  background-color: #a1a19b;
}

/* the calculator */
.calculator-container {
  flex: 1;
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.calculator-container .empty {
  flex: 1;
}
.calculator-container .text {
  font-size: 14px;
  text-align: end;
  color: #344d48;
}
.calculator-container .text.percentage {
  text-align: end;
}
.calculator-container .text.multiOp {
  margin-left: 5px;
  margin-right: 5px;
  font-size: 20px;
  text-align: start;
}
.calculator-container text.multiple {
  color: red;
}
.calculator-container .input {
  width: 80px;
  text-align: right;
  flex-grow: 0;
  font-size: 14px;
  color: #5c5f63;
}
.calculator-container .input.multiple {
  width: 25px;
  color: #ff0000;
  text-align: left;
}

  // js
  /** 页面中不变的数据 */
  constData: {
    fundRateValue: 3.25,
    commerRateValue: 4.90,
    fundMulity: 1,
    commerMulity: 1,
  },
  /**
   * 页面的初始数据
   */
  data: {
    loanType: 'providentFund', // commercial, combination
    fundAmount: 1,
    commerAmount: 1,
    yearIndex: 9, // range [0~30], default 10 years
    months: 120,
    baseFundRate: 3.25,
    baseCommerRate: 4.90,
    fundMulity: 1,
    commerMulity: 1,
    fundRateValue: 3.25,
    commerRateValue: 4.90,
  },
  /** 公积金贷款总额 */
  bindFundInput(e) {
    this.setData({
      fundAmount: e.detail.value,
    });
  },
  /** 商业贷款总额 */
  bindCommerInput(e) {
    this.setData({
      commerAmount: e.detail.value,
    });
  },
  /** 贷款年限更改 */
  bindYearChange(event) {
    const index = event.detail.value;
    this.setData({
      yearIndex: index,
      months: (parseInt(index) + 1) * 12,
    });
  },
  // 计算贷款年利率上浮情况
  fundMulity(e) {
    let eValue = e.detail.value;
    const bRate = this.data.baseFundRate;
    if (!eValue) {
      eValue = this.constData.fundMulity;
    }
    this.setData({
      fundMulity: eValue,
      fundRateValue: (bRate * eValue).toFixed(2),
    });
  },
  commerMulity(e) {
    let eValue = e.detail.value;
    const bRate = this.data.baseCommerRate;
    if (!eValue) {
      eValue = this.constData.commerMulity;
    }
    this.setData({
      commerMulity: eValue,
      commerRateValue: (bRate * eValue).toFixed(2),
    });
  },

计算按钮及样式
<view>
  <button bindtap="bindCalculate" id=''>开始计算</button>
  <view class='hor-line'></view>
  <button bindtap="change">等本息 / 等本金</button>
  <view class='pay-first-month'>首月还款: </view>
  <button bindtap='bindToShowDetail'>还款明细</button>
</view>
.pay-first-month {
  text-align: center;
  flex: 1;
}
  // js
  data: {
    /* ... above all last section */
    type: 'interest', // 等额本息; principal: 等额本金
    firstMonth: 0,
  },
  bindCalculate: function(e) {
    const loanType = this.data.loanType;
    const months = this.data.months;
    let lendAmount = 0;
    let rate = 0;
    let rate2 = 0;
    let everyMonth = 0;
    if (loanType === 'providentFund') {
      rate = this.data.fundRateValue / 100;
      lendAmount = this.data.fundAmount * 10000;
      everyMonth = this.calculateMonth(lendAmount, rate, months);
    } else if (loanType === 'commercial') {
      rate2 = this.data.commerRateValue / 100;
      lendAmount = this.data.commerAmount * 10000;
      everyMonth = this.calculateMonth(lendAmount, rate2, months);
    } else {
      rate = this.data.fundRateValue / 100;
      rate2 = this.data.commerRateValue / 100;
      //lendAmount = (this.data.fundAmount + this.data.commerAmount) * 10000;
      let fAmount = this.data.fundAmount * 10000;
      let cAmount = this.data.commerAmount * 10000;
      console.log('fAmount' + fAmount + ', cAmount' + cAmount + ', rate' + rate + ',' + rate2);
      everyMonth = this.calculateMonth(fAmount, rate, months) + this.calculateMonth(cAmount, rate2, months);
    }
    this.setData({
      firstMonth: everyMonth.toFixed(2),
    });
    return everyMonth;
  },

  calculateMonth: function(lendAmount, rate, months) {
    const payType = this.data.type;
    const mRate = rate / 12;
    let amount = 0;
    if (payType === 'interest') {
      // 100000×0.566667%×(1+0.566667%)120/[(1+0.566667%)120-1]
      // everyMonth = this.justInterst(lendAmount, rate, months)
      let top = lendAmount * mRate * Math.pow((1 + mRate), months);
      let bottom = Math.pow((1 + mRate), months) - 1;
      console.log('just interest top:' + top + ' ' + bottom);
      amount = top / bottom;
    } else if (payType === 'principal') {
      // 100000/120 + (10000-已还)*0.566667%
      console.log('just principal:' + lendAmount + ', rate:' + rate);
      amount = (lendAmount / months) + (lendAmount - 0) * mRate;
    }
    return amount;
  },

编译执行

此时已经可以看到一个界面了

手机上预览

调试、真机调试

开发工具左上角,将调试器显示出来

真机调试

一直显示等待设备连接,其实手机端已经扫码完毕,小程序直接闪一下就没了。 微信bug,真机无法调试

解决这个问题后,其他的就跟模拟器的调试差不多了。Note网上说有个vmContext切换一下,

显示每个月的还款详细情况

动手试试显示详细信息

| 月份 | 本金 | 利息 | |:—-:|:—:|:—-:| | 1 | 70.64 | 27.08 | | 2 | 70.83 | 26.89 |

更新

03/09/2019

代码重构,对界面布局和导航栏的颜色做了一些调整

项目 Github 仓库

Github-minigram minigram-preview