0
点赞
收藏
分享

微信扫一扫

vue2自定义指令实现 el-input 输入数字,小数点两位 最高10位,不满足则截取符合规则的值作为新值

步骤 1:创建自定义指令

// 处理输入值,确保符合规则
function processValue(value) {
  // 过滤非数字和小数点
  let filtered = value.replace(/[^\d.]/g, '');
  const firstDotIndex = filtered.indexOf('.');
  
  // 处理多个小数点,保留第一个
  if (firstDotIndex !== -1) {
    filtered = filtered.substring(0, firstDotIndex + 1) + filtered.substring(firstDotIndex + 1).replace(/\./g, '');
  }
  
  // 分割整数和小数部分
  const parts = filtered.split('.');
  let integerPart = (parts[0] || '').slice(0, 10); // 整数最多10位
  let decimalPart = parts.length > 1 ? parts[1].slice(0, 2) : ''; // 小数最多两位
  
  // 处理以小数点开头的情况(如 ".98" → "0.98")
  if (filtered.startsWith('.') && integerPart === '') {
    integerPart = '0';
  }
  
  // 组合结果
  let newValue = integerPart;
  if (parts.length > 1 || filtered.endsWith('.')) {
    newValue += '.' + decimalPart;
  }
  
  return newValue;
}

// 注册自定义指令
Vue.directive('number', {
  bind(el, binding, vnode) {
    const input = el.querySelector('input.el-input__inner');
    if (!input) return;
    
    let composing = false; // 标记是否在输入法组合中
    
    const handler = (e) => {
      if (composing) return;
      const newVal = processValue(e.target.value);
      if (e.target.value !== newVal) {
        e.target.value = newVal;
        input.dispatchEvent(new Event('input', { bubbles: true })); // 触发更新
      }
    };
    
    // 输入法处理
    const compositionStart = () => { composing = true; };
    const compositionEnd = (e) => {
      composing = false;
      handler(e);
    };
    
    input.addEventListener('compositionstart', compositionStart);
    input.addEventListener('compositionend', compositionEnd);
    input.addEventListener('input', handler);
    
    // 保存处理函数以便解绑
    el._numberHandlers = { compositionStart, compositionEnd, handler };
    
    // 初始值处理
    const initialValue = vnode.componentInstance?.value ?? input.value;
    const processedVal = processValue(initialValue);
    if (initialValue !== processedVal) {
      vnode.componentInstance?.$emit('input', processedVal);
    }
  },
  
  update(el, binding, vnode) {
    const input = el.querySelector('input.el-input__inner');
    const currentValue = vnode.componentInstance?.value ?? input?.value;
    if (currentValue === undefined) return;
    
    const newVal = processValue(currentValue);
    if (currentValue !== newVal) {
      vnode.componentInstance?.$emit('input', newVal);
    }
  },
  
  unbind(el) {
    const input = el.querySelector('input.el-input__inner');
    if (input && el._numberHandlers) {
      const { compositionStart, compositionEnd, handler } = el._numberHandlers;
      input.removeEventListener('compositionstart', compositionStart);
      input.removeEventListener('compositionend', compositionEnd);
      input.removeEventListener('input', handler);
      delete el._numberHandlers;
    }
  }
});

步骤 2:在组件中使用指令

<template>
  <el-input v-number v-model="inputValue"></el-input>
</template>

<script>
export default {
  data() {
    return {
      inputValue: ''
    };
  }
};
</script>

功能说明

  1. 过滤非数字字符:只允许输入数字和小数点。
  2. 限制小数点数量:确保只保留第一个小数点,后续的自动移除。
  3. 整数部分限制:最多输入 10 位整数,超长部分截断。
  4. 小数部分限制:最多输入 2 位小数,超长部分截断。
  5. 输入法兼容:处理中文输入法状态,避免中途过滤。
  6. 初始值处理:当初始值不符合规则时自动修正。
  7. 实时更新:通过触发 input 事件确保 v-model 同步更新。

注意事项

  • 该指令依赖于 Element UI 的 el-input 结构,确保内部输入框的类名为 el-input__inner
  • 处理后的值会覆盖用户输入,确保始终符合规则。
  • 支持输入法组合输入(如中文拼音),提升用户体验。
举报

相关推荐

0 条评论