vant 组件库限制 输入框只能修改 x 个字符

需求背景:

用户通过 OCR 识别出身份证结果后回填值页面内,但是只允许修改 3 个字符,新增删除或修改超过3个字符后还原为原始字符

版本

vue.2.6.14

vant.2.x latest

代码:

 <van-field
          v-model="enterInfo.legalName"
          v-limit-input="{ original: BACK_INFO.legalName, limit: 3 }"
          name="legalName"
          label="姓名"
          placeholder="请输入姓名"
          required
          :rules="[{ required: true, message: '请输入姓名' }]"
        ></van-field>

// BACK_INFO 是识别结果的备份数据
// enterInfo 是页面中所有表单控件双向绑定的变量
import { feedback } from "@utils/toast";
import Vue from "vue";

/**
 * Vue 指令,用于限制输入字段中可以修改的字符数量。
 * 它还会跟踪对输入字段所做的更改。
 * @example
 * <input v-limit-input="{ original: '123456', limit: 3, tips: '最多只能修改3个字符' }" />
 */
Vue.directive("limit-input", {
  /**
   * 在包含组件的 VNode 及其子 VNode 更新后调用。
   * @param {HTMLInputElement | any} el - 绑定指令的元素。
   * @param {Object} binding - 包含指令的名称、值、旧值、表达式、参数和修饰符的对象。
   * @param {Object} vnode - 绑定指令的 Vue 节点。
   */
  update(el: HTMLInputElement | any, binding, vnode) {
    const { original = "", limit = 3, tips } = binding.value; // 从指令的值中获取原始内容、限制长度和提示信息
    // 获取el下的input
    const inputEl = el.querySelector("input");
    if (!inputEl || original == inputEl.value) return;

    // 计算用户修改的字符数量
    const diffCount = getDiffCount(original, inputEl.value);
    const actionType = getActionType(original, inputEl.value);

    // 如果用户添加字符且不超过限制,则允许
    if (actionType === "add" && diffCount <= limit) {
      return;
    }
    // 如果用户删除字符且不超过限制,则允许
    if (actionType === "delete" && diffCount <= limit) {
      return;
    }

    // 根据不同的操作类型判断是否超出限制
    if (actionType === "modify" && diffCount > limit) {
      feedback.msg(tips || `最多只能修改${limit}个字符`, { closeOnClick: true });
      inputEl.value = original.substr(0, limit); // 截取前limit个字符
      el.__vue__.$emit("input", inputEl.value);
    } else if (actionType === "add" && inputEl.value.length > limit) {
      feedback.msg(tips || `最多只能添加${limit}个字符`, { closeOnClick: true });
      inputEl.value = original; // 恢复原始值
      el.__vue__.$emit("input", inputEl.value);
    } else if (actionType === "delete" && original.length - inputEl.value.length > limit) {
      feedback.msg(tips || `最多只能删除${limit}个字符`, { closeOnClick: true });
      inputEl.value = original; // 恢复原始值
      el.__vue__.$emit("input", inputEl.value);
    }
  },
});

/**
 * 计算两个字符串之间不同字符的数量
 */
function getDiffCount(oldStr: string, newStr: string) {
  if (!oldStr || !newStr) return 0;
  const maxLength = Math.max(oldStr.length, newStr.length);
  let count = 0;
  for (let i = 0; i < maxLength; i++) {
    if (oldStr[i] !== newStr[i]) {
      count++;
    }
  }
  return count;
}

/**
 * 判断用户的操作类型:添加、删除、修改
 */
function getActionType(oldStr: string, newStr: string) {
  if (oldStr.length > newStr.length) {
    return "delete";
  } else if (oldStr.length < newStr.length) {
    return "add";
  } else {
    return "modify";
  }
}

// 导出指令
export default Vue.directive("limit-input");


// *****************
// feedback 是一个自定义封装的消息提示

使用:

// 引入
import limitInput from "@/composables/directive/limit-input";

export default {
  directives: {
    limitInput,
  },
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值