В любом случае, чтобы изменить ввод, чтобы отображались только последние 4 цифры, но только если они не наведены?

Например, если я введу 123456789 и оставлю фокус, ввод изменится на *****6789.

У меня есть рабочий пример, но я не уверен, что в нем нет потенциальных ошибок. Есть ли способ лучше?

Я пришел к этому методом проб и ошибок

import { useState } from "react";
import "./styles.css";

export default function App() {
  const [hovered, setHovered] = useState(false);
  const [testInput, setTestInput] = useState("");
  const showLastFourDigits = (value) => {
    if (value.length == 9) {
      const result = "*".repeat(value.length - 4) + value.slice(-4);
      return result;
    } else {
      return value;
    }
  };

  const onSubmit = (e) => {
    e.preventDefault();
    console.info(testInput);
  };

  return (
    <form className = "App">
      <input
        value = {!hovered ? showLastFourDigits(testInput) : testInput}
        onChange = {(e) => setTestInput(e.target.value)}
        onFocus = {() => setHovered(true)}
        onBlur = {() => setHovered(false)}
        maxLength = {9}
      />
      <button onClick = {onSubmit}>Submit</button>
      <p>testInput:{testInput}</p>
    </form>
  );
}

Песочница кода

Как вы могли видеть. Если я наведу на него курсор, он покажет полный ввод. Если я открою его, он станет *****6789. По причине, я не уверен, почему, но onChange не запустится, если я сделаю это таким образом. Это безопасно? Меня беспокоит, что если я нажму «Отправить», вместо 123456789 появится *****6789. Это рекомендуемый способ сделать это?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
111
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Похоже, вы хотите замаскировать и снять маску в ответ на два критерия: элемент фокус и наведение состояние… и кажется, что вы уже поняли логику focus и blur. Большой!

В JS нет события «hover», но его близкое приближение можно реализовать с помощью событий mouseenter и mouseleave. Логика для mouseenter и mouseleave аналогична focus и blur соответственно, за исключением того, что они должны работать только в том случае, если элемент не сфокусирован.

Имеет ли элемент фокус, можно определить в JS, сравнив его с document.activeElement. Вот минимальный воспроизводимый пример:

<style>body { font-family: sans-serif; }</style>
<div id = "root"></div><script src = "https://cdn.jsdelivr.net/npm/[email protected]/umd/react.development.js"></script><script src = "https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.development.js"></script><script src = "https://cdn.jsdelivr.net/npm/@babel/[email protected]/babel.min.js"></script>
<script type = "text/babel" data-type = "module" data-presets = "env,react">

// This Stack Overflow snippet demo uses UMD modules
const { StrictMode, useState } = React;

function maskAllExceptFinal(str, options = {}) {
  const { maskToken = "*", revealCount = 4 } = options;
  return str.length <= revealCount
    ? str
    : `${maskToken.repeat(str.length - revealCount)}${str.slice(-4)}`;
}

function App() {
  const [masked, setMasked] = useState(true);
  const [testInput, setTestInput] = useState("");

  const handleSubmit = (ev) => {
    ev.preventDefault();
    console.info(testInput);
  };

  const handleMask = (ev) => {
    const isFocused = document.activeElement === ev.currentTarget;
    switch (ev.type) {
      case "blur": {
        setMasked(true);
        break;
      }
      case "focus": {
        setMasked(false);
        break;
      }
      case "mouseenter": {
        if (!isFocused) setMasked(false);
        break;
      }
      case "mouseleave": {
        if (!isFocused) setMasked(true);
        break;
      }
    }
  };

  return (
    <form>
      <input
        onBlur = {handleMask}
        onChange = {(ev) => setTestInput(ev.target.value)}
        onFocus = {handleMask}
        onMouseEnter = {handleMask}
        onMouseLeave = {handleMask}
        maxLength = {9}
        value = {masked ? maskAllExceptFinal(testInput) : testInput}
      />
      <button onClick = {handleSubmit}>Submit</button>
      <p>testInput: {testInput}</p>
    </form>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

</script>

Это нормально, если вы не используете <form onSubmit= {function}> для обработки ввода: в этом случае маскированное значение (*****6789) будет передано в качестве входного значения.

Ответ принят как подходящий

Честно говоря, я бы не рекомендовал возиться с реальным значением только для достижения чисто визуального эффекта. Я делал это раньше и столкнулся с несколькими проблемами, которые поначалу не были очевидны. Некоторые вещи я вспоминаю:

  • щелчок по вводу не будет правильно устанавливать позицию курсора в некоторых браузерах (поскольку входное значение менялось в тот самый момент при нажатии, что делало недействительным положение выбора)
  • Измененное значение попадет в дальнейшую цепочку обработки и будет отправлено на серверную часть.
  • проверка прервется, поскольку входные данные, допускающие только числовой ввод, не могут содержать звездочки ***1233

И есть замечательная альтернатива без заморочек: Выполните переключение исключительно с помощью CSS. Поместите в DOM два разных элемента:

  • один из них — вход, содержащий фактическое значение (без изменений)
  • другой — это элемент, отображающий замаскированное значение (это может быть ввод с атрибутом «только для чтения», или элемент div, или что-то еще, что позволяет вам получить желаемый визуальный эффект)
  • вы используете :focus и :hover (и что еще вы хотите включить) для управления видимостью двух элементов
  • Свойство css pointer-events позволяет точно контролировать, какой элемент получает события наведения.

Вот пример, просто чтобы проиллюстрировать идею:

const maskedValue = maskAllExceptFinal(value)

<div className = "container">
  <input className = "actual-value" value = {value} onChange = {...} />
  <input className = "masked-display" value = {maskedValue} readonly aria-hidden = "true" />
</div>
.container {
  position: relative;
}

.container:hover {
  & .masked-display {
    display: none;
  }
}

.actual-value {
  // ...
}

.masked-display {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Другие вопросы по теме