从零撸一个pc端vue的ui组件库( 计数器组件 )

听到计数器这个名字很多人是不是一瞬间没有什么印象, 毕竟这个组件用的比较少,就是那种左边一个'-'右边一个'+', 控制某些数量的时候才会用到, 比如我之前做的商城小程序只有'下单'页面的规格弹出框里面才有他的身影, 如果是涉及到处理商品数量很频繁的业务场景应该会很常见吧, 但是不要看这个组件小, 编写它的时候坑还不少, 本次我们就来做一个计数器, 目标就是尽可能小, 尽可能的省性能.

1:需求分析

每次+1 -1是常态, 但是如果搞活动, 每次最少为+-2个或三个, 就要兼容一下了,( 举一个实际遇到的坑, 我们之前把用户限制为每次活动, 每个用户只能买2个, 但是没有做好防备, 导致用户可能这次只买一个, 而下次他再次购买的时候会提示每次只能买两个, 但显示他只点击了买一个, 因为他已经买过一个, 为了兼容这个问题, 搞得还要加莫名其妙的补救代码 )

中间的显示区应该可输入的, 用户想买1000个不可能让他+1+1+1..., 某些组件采用的是, 平时其为div, 点击之后变为input, 个人感觉完全没必要, 一个元素就够了, 何必搞两个元素, input状态下把他的默认样式去掉就好了.

左右两边要有限制, 很多时候会有限购一说, 比如我做的商城, 库存只有10个 或者单个用户最多购买3个, 最少买两个等等限制.

小数位数的显示一说... 这个其实我还真遇到过, 有一种需求叫做, 只要涉及数字就必须精确到后两位, 这种需求会导致后台同学对数据库做一定的限制, 从而我们传给后台的数据也就存在限制了.

2: 基本结构:

先展示一章普通状态的图, 让我们更直观的去完成它, 造型比较别致, 是本套组件的一个特点, 哈哈做的与别人一样会导致思想的禁锢, 自己写代码多尝试新的东西, 但是工作中一定要中规中矩, 以公司条款为准则.

从零撸一个pc端vue的ui组件库( 计数器组件 )

vue-cc-ui/src/components/InputNumber/index.js

import inputNumber from './main/input-number.vue' inputNumber.install = function(Vue) { Vue.component(inputNumber.name, inputNumber); }; export default inputNumber

vue-cc-ui/src/components/InputNumber/main/input-number.vue

<template> <div> // 左侧的':heavy_minus_sign:'符号 <div> // 自己封装的icon组件, 出镜率还挺高:smirk_cat:. <cc-icon/> </div> // 中间的显示与输入部分,让人又爱又恨的number属性 // 下面的属性就能干掉凡人的上下按钮 // input::-webkit-outer-spin-button, // input::-webkit-inner-spin-button { // -webkit-appearance: none; // } <input ref="input" type="number"> <div> <cc-icon/> </div> </div> </template>

这里我们选择吧input与button放在一个div里面, 且同级别这种方式, 与其他的不太一样, 因为这样更直观, 而且也足够实现我想要的功能.

3: 事件的绑定

// 减少 <div @click='reduce'> // 增加 <div @click="add"> // 输入框的监控 <input ref="input" type="number" @input="inputChange($event)">

这里我们有个问题, 就是本组件采用的是v-model的形式编写, v-model有一些弊端, 在测试的时候我发现, 比如说用户为多个组件绑定了相同的v-model会导致无限渲染的bug, 下面会解读解决这类bug的相关代码.

prpos

props: { max: { type: Number }, // 数字不传默认是undefined min: { type: Number }, step: { // 每次计算的单位 type: Number, default: 1 }, value: { // 绑定的数值, 这里允许两种type, 为了方便用户书写,具体判断下面我们自己写 type: [String, Number], required: true }, precision: { // 显示小数点后几位数 type: Number, validator(value) { if (value < 1 || value === undefined) { return 1; } else { return parseInt(value); } } } },

add 方法的实现

add() { // 很可能用户就输入了一个string属性, // 1: 比如后台返回的就是字符串; // 2: input框输入的就是字符串类型; // 3: 用v-model绑定了同样的值的其他组件赋予了这个值string类型; let num = Number(this.value) + this.step; // 加上固定的长度 // 这里我们抽象出一个专门负责数值的变化的函数 this.emitVal(num); },

reduce 方法的实现

reduce() { let num = Number(this.value) - this.step; this.emitVal(num); },

监听input框的输入事件

inputChange(e) { // 这里就有可能出现string类型的了 this.emitVal(Number(e.target.value)); },

关键性的赋值函数

emitVal

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/769d2f4adf1ebd2e26ffbfdfe289e5f8.html