emitVal(newVal) { let { max, min } = this; // 不传参数的时候默认值就是undefined // 对这个值的限制就是, max之内, min以上 if (max !== undefined && newVal > max) newVal = max; if (min !== undefined && newVal < min) newVal = min; // 这里兼容一下位数控制 let value = Number(newVal).toFixed(this.precision); // 这个oldVal下面会解释:point_down: if (value === this.oldVal) return; this.oldVal = ls; // 发出两个事件, 一个负责改变value, 一个负责返回给用户 // 毕竟用户不可能监听input事件然后再把值附上去, 太麻烦 this.$emit("input", value); this.$emit("change", value); // 这一步很重要 // 下面会详细说 this.$refs.input.value = value; }
上面遗留的问题,这里解释一下.
oldVal: 能防止很多多余的改变, 比如说用户复制粘贴了一组数进来, 这个数大于max, 但是当时显示的数值就是max, 所以就不用渲染了, 或者v-model不止绑定了这个组件, 还绑定了其他各种组件, 导致值超出范围, 这边也会进行相应的限制, 而这个oldVal 就是上一个合法的值, 所以在做完检测之后, 检测通过的数值要赋值给他.
this.$refs.input.value = value; 这一步看似很没用, 因为输入框里面的是value, value改变input里面的值自然会改变, 但是实际测试并不是这样, 问题也是出现在v-model上, 绑定很多的时候会出现值的不改变, 可能是vue的机制问题, 而且他要放在 this.$emit(....);下面操作, 如果放在上面会导致多次执行, 因为他的执行会循环触发input的监听事件, 多次试验之后, 还是放在这里没有bug.
上面的两个问题都是涉及到v-model的问题, 下面还有一个同类的问题, 我们来看看.
对value进行的监控
因为value的变化, 不一定全是 通过+-输入这三种方式, 还有第三方通过v-model的方式, 还有用户手动乱填的方式.
watch: { value: { handler() { // 为了解决, 多组件共同v-model采用的这个方法, 也算是另辟蹊径了 let { value, time } = this; clearTimeout(time); // 毕竟把它放入宏任务Macrotasks可以躲过很多无限循环. time = setTimeout(() => { if (value !== undefined) this.emitVal(value); }); }, // 这个是开启进页面的瞬间就出发一次的意思, 很有用, 但是数据稍大会消耗性能, 慎用 // watch还有一个deep属性, 更是吃性能吃的厉害, 可以深度监控里面的数据 immediate: true } }
上面的问题都是基于v-model的, 所以很早就有人剔除双向绑定的坏处, 封装越多的组件感觉就越明显.
4: 关于样式的判定
在计算属性里面我们队当前值进行了监控, 返回的是置灰的颜色, 这个让用户自定的意义不大, 所以直接写了.
computed: { valueMin() { if (this.value === this.min) return "#bbbbbb"; return ""; }, valueMax() { if (this.value === this.max) return "#bbbbbb"; return ""; } },
dom, 点击到了最大值的话就会置灰, 我们上面已经阻止了继续点击的渲染
<cc-icon size='25px' :color="valueMax" />
做点有意思的事
slot是个自由度很高的标签
把左右按钮都包上, 让用户可以自己定义显示的标签是什么样子的
<div @click='reduce'> <slot> <cc-icon size='25px' :color='valueMin' /> </slot> </div> vue-cc-ui/src/style/inputNumber.scss @import './common/var.scss'; @import './common/extend.scss'; @import './common/mixin.scss'; @import './config/index.scss'; @include b(input-number) { // 友好的小手 cursor: pointer; // 有个放大动画, 看过我文章的同学都知道, 操作类的组件, 我喜欢有一个悬停放大效果. transition:all .1s; align-items: center; display: inline-flex; background-color: white; &:hover { // 放大被其他组件挡住就划不来了 z-index: 6; transform: scale(1.2); } // 招牌阴影 @include commonShadow($--color-black); @include e(add) { @include flexCenter(); padding: 4px 6px; } @include e(reduce) { @include flexCenter(); padding: 4px 6px; } @include e(input) { // 去掉输入框的默认样式 border: none; outline:none; display: block; text-align: center; width:60px; height: 20px; } }
效果展示
end
总的来说是这些组件中比较简单的一个了, 有些坑能够让我更好的学习vue以及前端的思想, 总的来说挺有趣的.
大家继续一起学习,一起进步, 早日实现自我价值!!