输入动态加敏

94 阅读1分钟

前置知识

selectionStart、selectionEnd

获取输入框光标的起始位置

效果

s.gif

  • 当不是选中时,两个值是一致的。
  • 值是 0、1、2...(可以理解为当前位置前的长度)

setSelectionRange

可以设置光标的位置

setSelectionRange(selectionStart, selectionEnd)

效果预览

t.gif

这是使用 element-plus 做出的,如果是原生的监听 input 事件即可,不用事件捕获了

代码:

<template>
  <div class="main">
    <h2>输入框动态加敏</h2>

    <el-input
      clearable
      placeholder="请输入"
      v-model="formModel.encryptValue"
      @input.capture="handleEncryptValue($event)"
    >
    </el-input>

    <p>原始值:{{ formModel.value }}</p>
  </div>
</template>
<script setup>
import { onMounted, reactive, nextTick } from "vue";

let formModel = reactive({
  value: "",
  encryptValue: "",
});

// 思路:比对当前输入框的值与上一次的值的长度,可以判断出长度是否变化以及的变化的长度
// 如果是新增,原始值插入新增的值
// 如果是删除,原始值删除变化的长度
async function handleEncryptValue(event) {
  let target = event.target;
  // 获取位置
  const selectionStart = target.selectionStart;

  // 上一次的值与当前值
  let prevValue = formModel.value;
  const curValue = target.value;

  // 判断是新增还是删除,以及变化的长度
  let changeLen = curValue.length - prevValue.length;
  const isAdd = changeLen > 0;
  const num = Math.abs(changeLen);

  let value = "";

  if (isAdd) {
    // 比如从 123 变成了 1243 我们就需要从 2 这个位置进行截取处理
    value =
      prevValue.slice(0, selectionStart - num) +
      curValue.slice(selectionStart - num, selectionStart) +
      prevValue.slice(selectionStart - num);
  } else {
    value =
      prevValue.slice(0, selectionStart) +
      prevValue.slice(selectionStart + num);
  }
  formModel.value = value;
  formModel.encryptValue = formatter(value);

  await nextTick();

  if (target.setSelectionRange) {
    target.setSelectionRange(selectionStart, selectionStart);
  }
}

// 格式化
function formatter(value, rule = "x****xxxx") {
  let valueList = value.split("");
  let ruleList = rule.split("");
  return valueList
    .map((item, index) => {
      return ruleList[index] === "*" ? "*" : item;
    })
    .join("");
}
</script>
<style scoped>
.main {
  width: 400px;
  height: 400px;
  margin: 100px auto;
}
</style>