• element-ui :封装el-input 遇到的问题


    因项目中有多处输入框要求只能输入整数或者浮点数, el-input 设置type=number 火狐浏览器这个属性是无效的; 所以就想到了 使用el-input type=text 输入的时候 正则匹配, 只能输入整数或者浮点数; 所以为了方便使用,需要对第三方库el-input 进行封装。

    1. 初始封装的组件Number-input.vue 代码如下:

    1. <template>
    2. <el-input
    3. :value="value"
    4. v-bind="$attrs"
    5. type="text"
    6. @input="handleInput"
    7. />
    8. </template>
    9. <script>
    10. import Big from 'big.js';
    11. export default {
    12. inheritAttrs: false,
    13. props: {
    14. value: {
    15. type: String | Number,
    16. default: ''
    17. },
    18. precision: {
    19. type: Number,
    20. validator(val) {
    21. return val >= 0 && val === parseInt(val, 10);
    22. }
    23. },
    24. minPrecision: {
    25. type: Number,
    26. validator(val) {
    27. return val >= 0 && val === parseInt(val, 10);
    28. }
    29. },
    30. maxPrecision: {
    31. type: Number,
    32. default: Infinity,
    33. validator(val) {
    34. return val >= 0 &&(val === parseInt(val, 10) || val === Infinity);
    35. }
    36. },
    37. isNumber: {
    38. type: Boolean,
    39. default: false
    40. },
    41. max: {
    42. type: String | Number,
    43. default: Infinity
    44. },
    45. min: {
    46. type: String | Number,
    47. default: -Infinity
    48. }
    49. },
    50. methods: {
    51. handleInput(val) {
    52. console.log('ssssss===', val)
    53. let reg = ''
    54. if(this.maxPrecision === Infinity) {
    55. // this.$emit('input', val)
    56. reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,20})?).*$`, 'g')
    57. this.$emit('input', val.replace(reg ,'$1'))
    58. } else if(this.maxPrecision >= 0) {
    59. // 正则不能输入最大位数
    60. reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,${this.maxPrecision}})?).*$`, 'g')
    61. this.$emit('input', val.replace(reg ,'$1'))
    62. }
    63. val = val.replace(reg ,'$1')
    64. this.$emit('input', val)
    65. console.log('ssssss结束===', val)
    66. },
    67. handleInputChange(val) {
    68. console.log('handleInputChange====', val, this.precision)
    69. let newV = isNaN(val) ? '' : (val ? val.toString() : '')
    70. if(newV) {
    71. newV = this.getNewValue(val.toString())
    72. }
    73. this.$emit('input', newV)
    74. },
    75. getNewValue(val) {
    76. // 根据精度获取幂次数, 获取精度整数位 利用math.round 四舍五入 转成float类型 再除以相同的10次幂 1.345直接利用tofixed(2) 取2位精度 会有问题
    77. let newV = ''
    78. let bigNewV = new Big(val)
    79. let precisionArray = val.split('.')
    80. let precision = precisionArray?.[1]?.length??0
    81. if(this.minPrecision >= precision) {
    82. newV = bigNewV.toFixed(this.minPrecision)
    83. } else {
    84. newV = bigNewV.toFixed(precision)
    85. }
    86. return newV
    87. }
    88. }
    89. }
    90. </script>

    封装第三方组件主要用到 $atrrs 和 $listeners 

    v-bind="$attrs" v-on="$listeners" 

     $atrrs:接收父组件传过来的非class 和 style , 并且未在props  中注册使用的属性 

    $listeners :接收父组件传过来的非native 的事件

    (注:.native 事件是父组件本身的事件, 在vue 中.native 只能用于组件上,.native 修饰符的作用是:在一个组件的根元素上直接监听一个原生事件; 原生的标签上不能使用 比如直接在 会报错)

    2. 父组件 Add.vue  中使用

    1. <NumberInput
    2. :maxPrecision="0"
    3. v-model="quantity"
    4. placeholder="请输入"
    5. clearable />

     上述使用目前为止都是正常的;

    然后突然发现另外一个同事使用的时候 ,出现了问题!!!

    在封装的组件Number-input.vue中多写一个属性为了接收父组件传过来的事件再传给下一级:v-on="$listeners"

    1. <template>
    2. <el-input
    3. :value="value"
    4. v-bind="$attrs"
    5. v-on="$listeners"
    6. type="text"
    7. @input="handleInput"
    8. />
    9. </template>

    和上述对比 导致除了数字其他还能输入

    原因就是 el-input 源码中 通过 v-on="$listeners" 接收了 业务组件Add.vue 传过来的事件, Add.vue 使用v-model 实现双向绑定, 默认有一个input 事件; 所以 当输入框输入数据的时候 , el-input 源码 中 触发input 事件, 同时向外触发 this.$emit('input', event.target.value) , 这个会先后触发Number-input.vue 和 Add.vue 中的 input事件; Add.vue中默认的input 事件接收的是 el-input 源码中传过来的原始值,会覆盖掉 Number-input.vue 中传过来的值, 最终v-model 中的值接收的也是el-input 源码中传过来的原始值. 

    1. el-input 源码
    2. handleInput(event) {
    3. // should not emit input during composition
    4. // see: https://github.com/ElemeFE/element/issues/10516
    5. if (this.isComposing) return;
    6. // hack for https://github.com/ElemeFE/element/issues/8548
    7. // should remove the following line when we don't support IE
    8. if (event.target.value === this.nativeInputValue) return;
    9. console.log('el-input input事件====', event)
    10. this.$emit('input', event.target.value);
    11. // ensure native input value is controlled
    12. // see: https://github.com/ElemeFE/element/issues/12850
    13. this.$nextTick(this.setNativeInputValue);
    14. },

    知道了原因所在,如何修复该问题:

    1. Number-input 组件中的@input 和 @change事件 添加.native , 这样的话 el-input 源码中的 $emit('input' 就不会触发这两个事件 ; 这两个事件 会添加到 组件的根元素上 ; 看 el-input 源码可知 会添加到最外层的div 上; 然后 当我们输入数据的时候 ,首先$emit('input' 触发的是Add.vue 中的input 事件改变value 值;接着 通过冒泡 会触发父元素上的input 和 change事件, 在这 两个事件中 手动又去触发了 add.vue 中的input 事件(这个主要是自己怎么写), 改变了 value 值, 最终改了输入框的值

    2. Number-input.vue中监听value 值的变化 类似下面: 但是这种 不能 区分是input 还是change事件

    1. watch: {
    2. value: {
    3. handler(val, oldV) {
    4. let reg = ''
    5. if(this.maxPrecision === Infinity) {
    6. // this.$emit('input', val)
    7. reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,20})?).*$`, 'g')
    8. this.$emit('input', val.replace(reg ,'$1'))
    9. } else if(this.maxPrecision >= 0) {
    10. // 正则不能输入最大位数
    11. reg = new RegExp(`^\\D*(\\d*(?:\\.\\d{0,${this.maxPrecision}})?).*$`, 'g')
    12. this.$emit('input', val.replace(reg ,'$1'))
    13. }
    14. val = val.replace(reg ,'$1')
    15. this.$emit('input', val)
    16. }
    17. }
    18. },

  • 相关阅读:
    完整解析快速排序
    shell脚本入门之【变量的定义】
    2025武忠祥考研数学,视频百度网盘+基础全程课程PDF
    大数据 为什么用
    MySQL之如何复制一张表的数据
    笔记53:torch.nn.rnn() 函数详解
    Linux命令type和which的区别
    acwing周赛 排队问题--二分+单调栈的思想
    [含毕业设计论文+PPT+源码等]ssm家教服务系统小程序+Java后台管理系统|前后分离VUE
    【C语言】等边等腰三角形的判断
  • 原文地址:https://blog.csdn.net/u014105739/article/details/128001128