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 相关文章推荐
跟我一起学写jQuery插件开发方法(附完整实例及下载)
Apr 01 Javascript
js function定义函数使用心得
Apr 15 Javascript
jQuery实现动画效果的实例代码
May 07 Javascript
Angular企业级开发——MVC之控制器详解
Feb 20 Javascript
jQuery中的deferred使用方法
Mar 27 jQuery
从parcel.js打包出错到选择nvm的全部过程
Jan 23 Javascript
详解JavaScript的BUG和错误
May 07 Javascript
Element Input组件分析小结
Oct 11 Javascript
js中对象与对象创建方法的各种方法
Feb 27 Javascript
jQuery事件委托代码实践详解
Jun 21 jQuery
微信小程序动态添加和删除组件的现实
Feb 28 Javascript
JavaScript字符串转数字的简单实现方法
Nov 27 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 常用数组内部函数(Array Functions)介绍
2013/06/05 PHP
php session劫持和防范的方法
2013/11/12 PHP
ThinkPHP做文字水印时提示call an undefined function exif_imagetype()解决方法
2014/10/30 PHP
ThinkPHP删除栏目(实现批量删除栏目)
2017/06/21 PHP
php框架CodeIgniter使用redis的方法分析
2018/04/13 PHP
laravel5环境隐藏index.php后缀(apache)的方法
2019/10/12 PHP
Thinkphp5+Redis实现商品秒杀代码实例讲解
2020/12/29 PHP
jQuery学习笔记之Helloworld
2010/12/22 Javascript
对JavaScript客户端应用编程的一些建议
2015/06/24 Javascript
用户代理字符串userAgent可实现的四个识别
2015/09/20 Javascript
JavaScript中通过提示框跳转页面的方法
2016/02/14 Javascript
jQuery实现点击表格单元格就可以编辑内容的方法【测试可用】
2016/08/01 Javascript
JavaScript编写棋盘覆盖代码详解
2017/08/28 Javascript
react-native-fs实现文件下载、文本存储的示例代码
2017/09/22 Javascript
基于vue通用表单解决方案的思考与分析
2019/03/16 Javascript
vue移动端模态框(可传参)的实现
2019/11/20 Javascript
vue组件系列之TagsInput详解
2020/05/14 Javascript
Vue + ts实现轮播插件的示例
2020/11/10 Javascript
浅谈pandas中Dataframe的查询方法([], loc, iloc, at, iat, ix)
2018/04/10 Python
python计算阶乘和的方法(1!+2!+3!+...+n!)
2019/02/01 Python
python opencv摄像头的简单应用
2019/06/06 Python
PyTorch中Tensor的拼接与拆分的实现
2019/08/18 Python
Python函数参数类型及排序原理总结
2019/12/19 Python
python 消除 futureWarning问题的解决
2019/12/25 Python
Python3.8安装Pygame教程步骤详解
2020/08/14 Python
Photobook澳大利亚:制作相片书,婚礼卡,旅行相簿
2017/01/12 全球购物
TUMI马来西亚官方网站:国际领先的高品质商旅箱包品牌
2018/04/26 全球购物
SteelSeries赛睿官网:游戏外设和配件的领先制造商(耳机、键盘、鼠标和鼠标垫)
2018/06/17 全球购物
香港士多网上超级市场:Ztore
2021/01/09 全球购物
学生会主席就职演讲稿
2014/01/14 职场文书
公司委托书格式范文
2014/10/09 职场文书
刑事辩护授权委托书范本
2014/10/17 职场文书
学校党的群众路线教育实践活动总结材料
2014/10/30 职场文书
在校证明模板
2015/06/17 职场文书
婚礼迎宾词大全
2015/08/10 职场文书
“爱眼护眼,提前预防近视”倡议书3篇
2019/10/30 职场文书