Vue.js入门 0x8 组件(Component)(5)Demo——数字输入框
数字输入框只能输入数字,而且有两个快捷按钮,可以直接减1或加 1 。除此之外,还可以设置初始值、最大值、最小值,在数值改变时,触发一个自定义事件来通知父组件。
首先,在写代码前一定要明确需求,然后规划好API。一个Vue组件的API只来自props、events和slots,确定好这3部分的命名、规则,剩下的逻辑即使第一版没有做好,后续也可以迭代完善。但是API如果没有设计好,后续再改对使用者成本就很大了。
index.html 入口页
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>数字输入框组件</title>
</head>
<body>
<div id="app">
<!--在父组件引入input-number,并给他一个默认值5,最大值10,最小值0-->
<input-number v-model="value" :max="10" :min="0"></input-number>
<!--value是个关键的绑定值故用了v-model这样既实现了双向绑定也让API看起来很合理。-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="input-number.js"></script>
<script src="index.js"></script>
</body>
</html>
input-number.js 数字输入框组件
function isValueNumber(value){
return (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)|(^-?0{1}$)/).test(value+'');
}
Vue.component('input-number',{
//定义组件根节点
template:'\
<div class="input-number">\
<input\
type="text"\
:value="currentValue"\
@change="handleChange">\
<button \
@click="handleDown"\
:disabled="currentValue<=min">-</button> \
<button \
@click="handleUp"\
:disabled="currentValue>=max">+</button> \
</div>',
props:{
max:{
type:Number,
default:Infinity
},
min:{
type:Number,
default:-Infinity
},
value:{
type:Number,
default:0
}
},
/**
* Vue组件是单向数据流,所以无法从组件内部直接修改prop value 的值 。
* 解决办法也介绍过,就是给组件声明一个data,默认引用value的值,然后
* 在组件内部维护这个 data
*/
data:function(){
return {
currentValue:this.value
}
},
/**
* watch 选项用来监昕某个 prop 或 data 的改变 , 当它们发生变化时,
* 就会触发 watch 配置的函数,从而完成我们的业务逻辑
*/
watch:{
//监昕 currentValue 是为了当 currentValue 改变时,更新 value 。
currentValue:function(val){
//使用 v-model 时 改变 value
this.$emit('input',val);
//触发自定义事件 on-change ,用于告知父组件数字输入框的值有所改变
this.$emit('on-change',val);
},
//监听 value 是要知晓从父组件修改了 value
value:function(val){
/**
* this是指向当前组件实例的,所以可以直接调用this.updateValue(),
* 因为 Vue 代理了 props 、 data 、 computed 及 methods
*/
this.updateValue(val);
}
},
methods:{
/**
* 从父组件传递过来的 value 有可能是不符合当前条件的 (大于max,
* 或小于 min),所以在选项 methods 里写了一个方法 updateValue ,
* 用来过滤出一个正确的 currentValue 。
*/
updateValue:function(val){
if(val>this.max) val = this.max;
if(val<this.min) val = this.min;
this.currentValue = val;
},
handleDown:function(){
if(this.currentValue<=this.min) return;
this.currentValue -= 1;
},
handleUp:function(){
if(this.currentValue>=this.max) return;
this.currentValue +=1;
},
handleChange:function(event){
var val = event.target.value.trim();
var max = this.max;
var min = this.min;
if(isValueNumber(val)){
val = Number(val);
this.currentValue = val;
if(val>max){
this.currentValue = max;
}else if(val<min){
this.currentValue = min;
}
}else{
event.target.value = this.currentValue;
}
}
},
/**
* 在生命周期 mounted钩子里也调用了 updateValue()方法 ,是因为
* 第一次初始化时 , 也对 value 进行了过滤
*/
mounted:function(){
this.updateValue(this.value)
}
})
index. 根实例
var app = new Vue({
el:'#app',
data:{
value:5
}
});