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 相关文章推荐
Mootools 1.2教程 类(一)
Sep 15 Javascript
js 输出内容到新窗口具体实现代码
May 31 Javascript
JavaScript实现查找字符串中第一个不重复的字符
Dec 29 Javascript
jQuery中siblings()方法用法实例
Jan 08 Javascript
jsonp跨域请求数据实现手机号码查询实例分析
Dec 12 Javascript
jQuery qrcode生成二维码的方法
Apr 03 Javascript
JS弹性运动实现方法分析
Dec 15 Javascript
Html5+jQuery+CSS制作相册小记录
Dec 30 Javascript
Vue.js学习笔记之修饰符详解
Jul 25 Javascript
js实现轮播图的两种方式(构造函数、面向对象)
Sep 30 Javascript
vue实现pdf文档在线预览功能
Nov 26 Javascript
解决vue elementUI中table里数字、字母、中文混合排序问题
Jan 07 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转成EXE文件
2006/10/09 PHP
PHP通过插入mysql数据来实现多机互锁实例
2014/11/05 PHP
php+xml编程之xpath的应用实例
2015/01/24 PHP
py文件转exe时包含paramiko模块出错解决方法
2016/08/12 PHP
php 使用expat方式解析xml文件操作示例
2019/11/26 PHP
jQuery的.live()和.die() 使用介绍
2011/09/10 Javascript
判断是否安装flash player及当前版本的JS代码
2013/08/08 Javascript
同域jQuery(跨)iframe操作DOM(示例代码)
2013/12/13 Javascript
js统计页面的来访次数实现代码
2014/05/09 Javascript
AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法
2014/06/06 Javascript
jQuery 利用$.ajax 时获取原生XMLHttpRequest 对象的方法
2016/08/25 Javascript
深入理解Javascript箭头函数中的this
2017/02/13 Javascript
js实现下拉框效果(select)
2017/03/28 Javascript
Angular 4依赖注入学习教程之FactoryProvider配置依赖对象(五)
2017/06/04 Javascript
vue.js模仿京东省市区三级联动的选择组件实例代码
2017/11/22 Javascript
JS实现数组深拷贝的方法分析
2019/03/06 Javascript
[43:53]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第三场 8.22
2019/09/05 DOTA
[47:18]完美世界DOTA2联赛循环赛 IO vs FTD BO2第一场 11.05
2020/11/06 DOTA
python对html代码进行escape编码的方法
2015/05/04 Python
Python文档生成工具pydoc使用介绍
2015/06/02 Python
使用Python处理Excel表格的简单方法
2018/06/07 Python
Python实现简单石头剪刀布游戏
2021/01/20 Python
Pytorch 实现权重初始化
2019/12/31 Python
python使用turtle库绘制奥运五环
2020/02/24 Python
Pytorch中的自动求梯度机制和Variable类实例
2020/02/29 Python
pytorch读取图像数据转成opencv格式实例
2020/06/02 Python
美国家居装饰购物网站:Amanda Lindroth
2020/03/25 全球购物
英国时尚首饰品牌:Missoma
2020/06/29 全球购物
室内设计专业学生的自我评价分享
2013/11/27 职场文书
西安交大自主招生自荐信
2014/01/27 职场文书
酒店营销策划方案
2014/02/07 职场文书
社团活动总结范文
2014/04/26 职场文书
市场营销战略计划书
2014/05/06 职场文书
小学生母亲节演讲稿
2014/05/07 职场文书
2015年公路养护工作总结
2015/05/13 职场文书
SONY600GR,国产收音机厂商永远的痛
2022/04/05 无线电