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 相关文章推荐
js常用排序实现代码
Dec 28 Javascript
js渐变显示渐变消失示例代码
Aug 01 Javascript
关于extjs4如何获取grid修改后的数据的问题
Aug 07 Javascript
JS和Jquery获取和修改label的值的示例代码
Jan 15 Javascript
JS控制表单提交的方法
Jul 09 Javascript
Angularjs过滤器使用详解
May 25 Javascript
纯js实现悬浮按钮组件
Dec 17 Javascript
js实现PC端和移动端刮卡效果
Mar 27 Javascript
vue2.0+vuex+localStorage代办事项应用实现详解
May 31 Javascript
webpack4 处理CSS的方法示例
Sep 03 Javascript
vue打包之后生成一个配置文件修改接口的方法
Dec 09 Javascript
JavaScript实现获取两个排序数组的中位数算法示例
Feb 26 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
杏林同学录(六)
2006/10/09 PHP
谈谈你对Zend SAPIs(Zend SAPI Internals)的理解
2015/11/10 PHP
CI配置多数据库访问的方法
2016/03/28 PHP
PHPCMS2008广告模板SQL注入漏洞修复
2016/10/11 PHP
JavaScript 控制字体大小设置的方法
2016/11/23 Javascript
js实现百度地图定位于地址逆解析,显示自己当前的地理位置
2016/12/08 Javascript
AngularJS折叠菜单实现方法示例
2017/05/18 Javascript
jQuery Masonry瀑布流布局神器使用详解
2017/05/25 jQuery
浅谈JS封闭函数、闭包、内置对象
2017/07/18 Javascript
在微信小程序中渲染HTML内容的方法示例
2018/09/28 Javascript
vue中filters 传入两个参数 / 使用两个filters的实现方法
2019/07/15 Javascript
微信小程序商品详情页底部弹出框
2019/11/22 Javascript
es6中Promise 对象基本功能与用法实例分析
2020/02/23 Javascript
jquery实现加载更多&quot;转圈圈&quot;效果(示例代码)
2020/11/09 jQuery
centos下更新Python版本的步骤
2013/02/12 Python
Python中文件操作简明介绍
2015/04/13 Python
分享给Python新手们的几道简单练习题
2017/09/21 Python
Python爬虫实例_利用百度地图API批量获取城市所有的POI点
2018/01/10 Python
python通过TimedRotatingFileHandler按时间切割日志
2019/07/17 Python
python list转置和前后反转的例子
2019/08/26 Python
python列表切片和嵌套列表取值操作详解
2020/02/27 Python
Python实现自动打开电脑应用的示例代码
2020/04/17 Python
python实现启动一个外部程序,并且不阻塞当前进程
2020/12/05 Python
轻松掌握CSS3中的字体大小单位rem的使用方法
2016/05/24 HTML / CSS
Html5页面在微信端的分享的实现方法
2018/08/30 HTML / CSS
Original Penguin美国官网:布拉德皮特、强尼德普喜爱的服装品牌
2016/10/25 全球购物
马来西亚领先的在线礼品店:Giftr
2018/08/23 全球购物
Chicco婴儿用品美国官网:汽车座椅、婴儿推车、高脚椅等
2018/11/05 全球购物
造价工程师个人求职信
2013/09/21 职场文书
外贸主管求职简历的自我评价
2013/10/23 职场文书
采购主管岗位职责
2014/02/01 职场文书
乡村文明行动实施方案
2014/03/29 职场文书
班主任班级寄语大全
2014/04/04 职场文书
单位介绍信格式范文
2015/05/04 职场文书
建党伟业电影观后感
2015/06/01 职场文书
重阳节座谈会主持词
2015/07/03 职场文书