Element InputNumber 计数器的实现示例


Posted in Javascript onAugust 03, 2020

前言

这篇我们继续研究InputNumber。

基本实现

基本的准备工作过后,开始基本实现。

上测试代码:

<el-input-number v-model="num" @change="handleChange" :min="1" :max="10" label="描述文字">
</el-input-number>

上组件代码:

<template>
 <div
 :class="[
  'el-input-number',
 ]"
 >
 <span 
  class="el-input-number__decrease"
  role="button"
  :class="{'is-disabled': minDisabled}"
  @click="decrease"
 >
  <i class="el-icon-minus"></i>
 </span>
 <span
  class="el-input-number__increase"
  role="button"
  :class="{'is-disabled': maxDisabled}"
  @click="increase"
 >
  <i class="el-icon-plus"></i>
 </span>
 <el-input
  ref="input"
  :value="value"
  @input="value => $emit('input', value)"
 >
 </el-input>
 </div>
</template>

<script>
import ElInput from '../Input/index'

export default {
 name: 'ElInputNumber',
 props: {
 value: {},
 max: {
  type: Number,
  default: Infinity
 },
 min: {
  type: Number,
  default: -Infinity
 },
 },
 computed: {
 minDisabled() {
  return this.value - 1 < this.min;
 },
 maxDisabled() {
  return this.value + 1 > this.max;
 },
 },
 methods: {
 decrease() {
  if(this.minDisabled) return

  this.$emit('input', this.value - 1)
 },
 increase() {
  if(this.maxDisabled) return

  this.$emit('input', this.value + 1)
 }
 },
 components: {
 ElInput
 }
}
</script>

上效果:

Element InputNumber 计数器的实现示例

这次可以复用Input组件,两边加新增/减少两个按钮,实现加减逻辑。再控制最大值最小值的时候,禁用按钮,基本实现完成。

点击按钮持续增加/减少

现在添加:点击加减按钮的时候,不抬起鼠标,值就会持续增加/减少的特性。

要实现此功能,源码中用到了directive自定义指令,靠节流mousedown事件来实现持续点击效果。

写自定义命令:

import { once, on } from '../utils/dom';

export default {
 bind(el, binding, vnode) {
 let interval = null;
 let startTime;
 // binding.expression 就是decrease/increase 事件名称
 // handler就是对应的相应函数
 const handler = () => vnode.context[binding.expression].apply();
 const clear = () => {
  if (Date.now() - startTime < 100) {
  handler();
  }
  clearInterval(interval);
  interval = null;
 };

 on(el, 'mousedown', (e) => {
  if (e.button !== 0) return;
  startTime = Date.now();
  once(document, 'mouseup', clear);
  clearInterval(interval);
  // 实现节流
  interval = setInterval(handler, 100);
 });
 }
};

在组件中使用自定义命令:

import RepeatClick from '../../directives/repeat-click';

directives: {
 repeatClick: RepeatClick
},

<span 
 class="el-input-number__decrease"
 role="button"
 :class="{'is-disabled': minDisabled}"
 v-repeat-click="decrease"
>
 <i class="el-icon-minus"></i>
</span>
<span
 class="el-input-number__increase"
 role="button"
 :class="{'is-disabled': maxDisabled}"
 v-repeat-click="increase"
>
 <i class="el-icon-plus"></i>
</span>

禁用状态

  • 添加 { 'is-disabled': disabled } 到根节点样式上。
  • 添加:disabled="disabled"到el-input节点上。
  • 添加if(this.disabled) return 到decrease/increase方法上。

完成效果:

Element InputNumber 计数器的实现示例

步数

上测试代码:

<el-input-number v-model="num" :step="2"></el-input-number>

给组件添加step属性。在组件中把+/-1这样到代码替换为+/- this.step。

严格步数

step-strictly属性接受一个Boolean。如果这个属性被设置为true,则只能输入步数的倍数。

上测试代码:

<el-input-number v-model="num" :step="2" step-strictly></el-input-number>

要想实现严格步数,我们直接输入的值,会检查是不是step的倍数,如果不是,则换成step的倍数。这就不能直接把InputNumber的value直接绑定在内部的el-input上了。先在el-input的input事件记录输入的值。再在change事件中将值赋予给value,最后在watch.value上校验输入的值,并转换成step的倍数。

data() {
 return {
 currentValue: 0, // 缓存上次输入的值
 userInput: null, // 缓存当前输入的值
 };
},

<el-input
 ref="input"
 :disabled="disabled"
 :value="currentValue" // 变为绑定currentValue
 @input="handleInput"
 @change="handleInputChange"
>
</el-input>

// 先在el-input的input事件记录输入的值
handleInput(value) {
 this.userInput = value;
},
// 在change事件中将值赋予给value
handleInputChange(value) {
 let newVal = value === '' ? undefined : Number(value);
 
 if (!isNaN(newVal) || value === '') {
  this.setCurrentValue(newVal);
 }
 this.userInput = null;
},
setCurrentValue(newVal) {
 const oldVal = this.currentValue;

 if (newVal >= this.max) newVal = this.max;
 if (newVal <= this.min) newVal = this.min;
 if (oldVal === newVal) return;
 this.userInput = null;
 this.$emit('input', newVal);
 this.$emit('change', newVal, oldVal);
 this.currentValue = newVal;
},

watch: {
 // 在watch.value上校验输入的值,并转换成step的倍数
 value: {
 immediate: true,
 handler(value) {
  let newVal = value === undefined ? value : Number(value);
  
  // 设置严格步数的逻辑
  if (this.stepStrictly) {
   newVal = Math.round(newVal / this.step) * this.step
  }

  if (newVal >= this.max) newVal = this.max;
  if (newVal <= this.min) newVal = this.min;

  this.currentValue = newVal;
  this.userInput = null;
  this.$emit('input', newVal);
 }
 }
},

精度

上测试代码:

<el-input-number v-model="numPrecision" :precision="2" :step="0.1" :max="10"></el-input-number>

这里step变成小数了,那在累加得过程中,就会有0.1+0.2这样得精度问题出现了。element的解决思路是将值扩大精度倍进行计算,得到结果后再除以精度倍数。

increase() {
 if(this.maxDisabled || this.disabled) return
 const value = this.value || 0;
 const newVal = this._increase(value, this.step);

 this.setCurrentValue(newVal);
},
_increase(val, step) {
 if (typeof val !== 'number' && val !== undefined) return this.currentValue;
 // step是0.1,precisionFactor是10。
 const precisionFactor = Math.pow(10, this.numPrecision);

 return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor);
},

// 确保计算得结果0.10000000001这种误差情况会被消除
 toPrecision(num, precision) {
 if (precision === undefined) precision = this.numPrecision;
 return parseFloat(Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision));
},

在展示的时候,利用toFixed函数展示精度即可。

效果如下:

Element InputNumber 计数器的实现示例

尺寸

添加size属性,在根元素得样式添加size ? 'el-input-number--' + size : ''。

效果如下:

Element InputNumber 计数器的实现示例

按钮位置

设置 controls-position 属性可以控制按钮位置。

上测试代码:

<el-input-number v-model="num" controls-position="right" @change="handleChange" :min="1" :max="10">
</el-input-number>

通过controls-position='right',在组件内控制样式即可。

效果如下:

Element InputNumber 计数器的实现示例

总结

严格步数和精度这两个特性得逻辑稍有些复杂,需要多研究一会。

源码在码云: https://gitee.com/DaBuChen/my-element-ui/tree/input-number

到此这篇关于Element InputNumber 计数器的实现示例的文章就介绍到这了,更多相关Element InputNumber 计数器内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
让table变成exls的示例代码
Mar 24 Javascript
node.js中使用node-schedule实现定时任务实例
Jun 03 Javascript
js实现接收表单的值并将值拼在表单action后面的方法
Nov 23 Javascript
jQuery页面元素动态添加后绑定事件丢失方法,非 live
Jun 16 Javascript
jquery实时获取时间的简单实例
Jan 26 Javascript
如何用JS/HTML将时间戳转换为“xx天前”的形式
Feb 06 Javascript
微信小程序实现弹出菜单功能
Jun 12 Javascript
element-ui使用导航栏跳转路由的用法详解
Aug 22 Javascript
微信小程序HTTP接口请求封装的实现
Feb 21 Javascript
C#程序员入门学习微信小程序的笔记
Mar 05 Javascript
javascript防抖函数debounce详解
Jun 11 Javascript
vue 组件之间事件触发($emit)与event Bus($on)的用法说明
Jul 28 Javascript
解决Vue的文本编辑器 vue-quill-editor 小图标样式排布错乱问题
Aug 03 #Javascript
Vue 根据条件判断van-tab的显示方式
Aug 03 #Javascript
在vue中使用el-tab-pane v-show/v-if无效的解决
Aug 03 #Javascript
Vue解决echart在element的tab切换时显示不正确问题
Aug 03 #Javascript
js实现点击上传图片并设为模糊背景
Aug 02 #Javascript
jQuery实现雪花飘落效果
Aug 02 #jQuery
原生js+canvas实现贪吃蛇效果
Aug 02 #Javascript
You might like
PHP数据类型的总结分析
2013/06/13 PHP
在 Laravel 6 中缓存数据库查询结果的方法
2019/12/11 PHP
js监听滚动条滚动事件使得某个标签内容始终位于同一位置
2014/01/24 Javascript
jQuery 实现侧边浮动导航菜单效果
2014/12/26 Javascript
jQuery使用元素属性attr赋值详解
2015/02/27 Javascript
Hallo.js基于jQuery UI所见即所得的Web编辑器
2016/01/26 Javascript
JavaScript中的this引用(推荐)
2016/08/05 Javascript
JS中常用的正则表达式
2016/09/29 Javascript
基于JS实现bookstore静态页面的实例代码
2017/02/22 Javascript
微信小程序 动态绑定事件并实现事件修改样式
2017/04/13 Javascript
微信小程序基于本地缓存实现点赞功能的方法
2017/12/18 Javascript
微信小程序按钮点击跳转页面详解
2019/05/06 Javascript
详解vue或uni-app的跨域问题解决方案
2020/02/21 Javascript
[01:32]TI奖金增速竟因它再创新高!DOTA2勇士令状不朽珍藏Ⅰ饰品欣赏
2018/05/18 DOTA
[01:18:33]Secret vs VGJ.S Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
python取代netcat过程分析
2018/02/10 Python
完美解决Pycharm无法导入包的问题 Unresolved reference
2018/05/18 Python
python控制windows剪贴板,向剪贴板中写入图片的实例
2018/05/31 Python
详解Python 中sys.stdin.readline()的用法
2019/09/12 Python
Numpy之将矩阵拉成向量的实例
2019/11/30 Python
flask开启多线程的具体方法
2020/08/02 Python
PyTorch中的拷贝与就地操作详解
2020/12/09 Python
美国派对用品及装饰品网上商店:Shindigz
2016/07/30 全球购物
企业行政文员岗位职责
2013/12/03 职场文书
配件采购员岗位职责
2013/12/03 职场文书
大学生文员专业个人求职信范文
2014/01/05 职场文书
读群众路线心得体会
2014/03/07 职场文书
个人承诺书
2014/03/26 职场文书
校长寄语大全
2014/04/09 职场文书
实习公司领导推荐函
2014/05/21 职场文书
2014党员学习《反腐倡廉警示教育读本》思想汇报
2014/09/13 职场文书
关于长城的导游词
2015/01/30 职场文书
刑事撤诉申请书
2015/05/18 职场文书
导游词之山东八大关
2019/12/18 职场文书
浅谈resultMap的用法及关联结果集映射
2021/06/30 Java/Android
react 路由Link配置详解
2021/11/11 Javascript