侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

前端  /  管理员 发布于 4年前   366

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

1:需求分析

  • 每次+1 -1是常态, 但是如果搞活动, 每次最少为+-2个或三个, 就要兼容一下了,( 举一个实际遇到的坑, 我们之前把用户限制为每次活动, 每个用户只能买2个, 但是没有做好防备, 导致用户可能这次只买一个, 而下次他再次购买的时候会提示每次只能买两个, 但显示他只点击了买一个, 因为他已经买过一个, 为了兼容这个问题, 搞得还要加莫名其妙的补救代码 )
  • 中间的显示区应该可输入的, 用户想买1000个不可能让他+1+1+1..., 某些组件采用的是, 平时其为div, 点击之后变为input, 个人感觉完全没必要, 一个元素就够了, 何必搞两个元素, input状态下把他的默认样式去掉就好了.
  • 左右两边要有限制, 很多时候会有限购一说, 比如我做的商城, 库存只有10个 或者单个用户最多购买3个, 最少买两个等等限制.
  • 小数位数的显示一说... 这个其实我还真遇到过, 有一种需求叫做, 只要涉及数字就必须精确到后两位, 这种需求会导致后台同学对数据库做一定的限制, 从而我们传给后台的数据也就存在限制了.

2: 基本结构:

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

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

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

3: 事件的绑定

// 减少 
// 增加
// 输入框的监控

这里我们有个问题, 就是本组件采用的是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

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, 点击到了最大值的话就会置灰, 我们上面已经阻止了继续点击的渲染

做点有意思的事

slot是个自由度很高的标签

把左右按钮都包上, 让用户可以自己定义显示的标签是什么样子的

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以及前端的思想, 总的来说挺有趣的.

大家继续一起学习,一起进步, 早日实现自我价值!!

下一集准备聊聊 tab切换组件的相关知识;

github: 链接描述


  • 上一条:
    非常实用的jQuery代码段集锦【检测浏览器、滚动、复制、淡入淡出等】
    下一条:
    Vue-cli3.X使用px2 rem遇到的问题及解决方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客