基本使用示例
在介绍 Vue 的工作原理之前,我们先通过一个个税计算器示例,由简到繁地演进,以熟悉 Vue 的属性变化侦测及组件化开发的基本使用方式。
第一步:自动更新视图
我们期望实现一个可以根据用户输入的税前收入,来实时计算纳税额、税后到手金额的小工具。
首先,我们要引入 Vue.js。这里采用最简单的方式,即直接在 HTML 文件中通过 <script>
标签从 CDN 服务商引入 vue.js
:
<!-- 开发环境版本,包含了用帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 这里是 vue app 在文档中的挂载点 -->
<div id="app">
<div><label>税前月收入:</label><input v-model="income"></div>
<div><label>五险一金数额: </label>{{ result.profit }}</div>
<div><label>税后收入:</label>{{ result.real_income }}</div>
<div><label>实际纳税额:</label>{{ result.tax }}</div>
</div>
然后,我们需要实现一个根据税前月收入、个税起征点等参数来计算纳税额、税后收入、五险一金数额的纯函数 taxCalculator()
,该函数的核心算法基于我国内地目前的个税法案来实现,如下所示:
/**
* 中国个税计算算法
* 算法参考:http://www.gerensuodeshui.cn/
*/
function taxCalculator(options = {
base: 3500,
income: 10000,
profit: 0,
}) {
const base = options.base || 3500;
// 税前收入
const income = Number(options.income) || 0;
// 五险一金缴纳额
const profit = options.profit || Math.round(income * 0.202);
const income_after_profit = Math.round(income - profit);
// 应纳税所得额
let income_for_tax = income_after_profit - base;
if (income_for_tax < 0) {
income_for_tax = 0;
}
// 应纳税所得额(不含税)表
const list = [0, 1455, 4155, 7755, 27255, 41255, 57505, 1000000000000];
// 税率表
const rate = [0, 0.03, 0.1, 0.20, 0.25, 0.3, 0.35, 0.45];
// 速算扣除数表
const minus = [0, 0, 105, 555, 1005, 2775, 5505, 13505];
let index = list.findIndex((item, i) => {
return (item > income_for_tax) && (list[i - 1] < income_for_tax);
});
let tax = 0;
if (income_for_tax) {
tax = Number(income_for_tax * rate[index] - minus[index]).toFixed(2);
}
let real_income = (income_after_profit - Number(tax)).toFixed(2); // 税后收入
return {income, profit, real_income, tax};
}
最后,我们使用 Vue 来监听用户的输入,实时计算结果:
const app = new Vue({
el: '#app',
data: {
income: 0
},
computed: {
result: function() {
return taxCalculator({income: this.income})
}
}
});
到此为止,我们的个税计算器就已经实现完成了,效果如下图所示。
第二步:添加子组件并与父组件通信
2018 年两会期间,关于提升个税起征点的议题成为社会讨论的焦点之一。我们在第一步里使用的 3500 元起征点,是 2011 年 9 月 1 日起实施的。我们可以在第一步的基础上,添加一个功能,让用户可以设置计算个税的起征点数值。
简便起见,我们直接使用 Vue.component
方法在全局定义一个名为 user-settings
的子组件。
/**
* 定义一个用于设置个税起征点的组件
*/
Vue.component('user-settings', {
template: `
<div>
<label>选择个税起征点</label>
<select v-on:change="onSelectChange">
<option v-for="item in list">{{ item }}</option>
</select>
</div>`,
data: function () {
return {
base: 3500,
// 可选的个税起征点数值
list: [3500, 4000, 5000, 7000, 10000],
}
},
methods: {
// 子组件上的事件
onSelectChange: function(event) {
var target = event.target;
var value = Number(target.value);
this.$emit('settings', {
base: value,
});
}
}
});
在 HTML 中,可以像 Web Components 规范约定的那样直接使用标签名嵌入子组件,使用 v-on:settings
监听子组件发布的名为 settings
事件:
<div id="app">
<!-- 省略其他代码 -->
<user-settings v-on:settings="onSettingsChange"></user-settings>
</div>
最外层的 Vue APP 则改写为:
// Vue app
const app = new Vue({
el: '#app',
data: {
income: 0,
base: 3500,
},
computed: {
result: function() {
return taxCalculator({income: this.income, base: this.base});
}
},
methods: {
onSettingsChange: function(settings) {
this.base = settings.base;
}
}
});
调整之后的效果如下图所示。可以看到,对于税前收入 1 万元的劳动者来说,个税起征点如果从 3500 元提高到 5000 元,那么可以减少 43% 的纳税额。