密码输入时的隐藏显示和显示

前些天发现了一个人工智能学习网站,通俗易懂,风趣幽默,最重要的屌图甚多,忍不住分享一下给大家。点击跳转到网站

我们先看一下展示:
在这里插入图片描述
代码展示:

<form action="">
  <div class="form-group">
    <label for="password">Password</label>
    <input id="password" type="password" required />
    <button type="button" title="Reveal Password" aria-pressed="false">
      <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <mask id="eye-open">
            <path d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12V20H12H1V12Z" fill="#D9D9D9" stroke="black" stroke-width="1.5" stroke-linejoin="round" />
          </mask>
          <mask id="eye-closed">
            <path d="M1 12C1 12 5 20 12 20C19 20 23 12 23 12V20H12H1V12Z" fill="#D9D9D9" />
          </mask>
        </defs>
        <path class="lid lid--upper" d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
        <path class="lid lid--lower" d="M1 12C1 12 5 20 12 20C19 20 23 12 23 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
        <g mask="url(#eye-open)">
          <g class="eye">
            <circle cy="12" cx="12" r="4" fill="currentColor" />
            <circle cy="11" cx="13" r="1" fill="black" />
          </g>
        </g>
      </svg>
      <span class="sr-only">Reveal</span>
    </button>
  </div>
</form>
@font-face {
  font-family: "Geist Mono";
  src: url("https://assets.codepen.io/605876/GeistMonoVariableVF.ttf") format("truetype");
}

:root {
	--grid-offset: calc(50% + 80px);
	--color: hsl(0 0% 6%);
	--bg: hsl(0 0% 96%);
	--color-alpha: hsl(0 0% 60%);
	--selection: hsl(0 0% 80%);
	--bg-size: 180px;
	--grid-line: hsl(0 0% 80%);
	--input-bg: hsl(0 0% 100% / 0.2);
	--grid-accent: hsl(280 0% 10% / 0.1);
	--glint: white;
	--button-shade: 80%;
}
:root:focus-within {
	--grid-accent: hsl(280 0% 10% / 0.35);
}

@media(prefers-color-scheme: dark) {
	:root {
		--button-shade: 30%;
		--glint: black;
		--grid-accent: hsl(280 0% 80% / 0.1);
		--selection: hsl(0 0% 20%);
		--color: hsl(0 0% 98%);
		--bg: hsl(0 0% 6%);
		--color-alpha: hsl(0 0% 50%);
		--grid-line: hsl(0 0% 12%);
		--input-bg: hsl(0 0% 0% / 0.2);
	}
	:root:focus-within {
		--grid-accent: hsl(280 0% 80% / 0.35);
	}
}

*,
*:after,
*:before {
	box-sizing: border-box;
}


body {
	display: grid;
	place-items: center;
	min-height: 100vh;
	font-family:  'Geist Mono', sans-serif, system-ui;
	color: var(--color);
	background: var(--bg);
/*	background: black;*/
}

body::before {
	content: "";
	transition: background 0.2s;
	background:
		/*	How to create one square */
		linear-gradient(var(--grid-accent) 0 2px, transparent 2px calc(100% - 2px), var(--grid-accent) calc(100% - 2px)) calc((var(--grid-offset) - (var(--bg-size) * 2)) - 1px) calc((var(--grid-offset) - var(--bg-size)) - 1px) / calc(var(--bg-size) + 2px) calc(var(--bg-size) + 2px) no-repeat,
		linear-gradient(90deg, var(--grid-accent) 0 2px, transparent 2px calc(100% - 2px), var(--grid-accent) calc(100% - 2px)) calc((var(--grid-offset) - (var(--bg-size) * 2)) - 1px) calc((var(--grid-offset) - var(--bg-size)) - 1px) / calc(var(--bg-size) + 2px) calc(var(--bg-size) + 2px) no-repeat,
		linear-gradient(transparent calc(var(--bg-size) - 2px), var(--grid-line) calc(var(--bg-size) - 2px) var(--bg-size)) var(--grid-offset) var(--grid-offset) / 100% var(--bg-size),
		linear-gradient(90deg, transparent calc(var(--bg-size) - 2px), var(--grid-line) calc(var(--bg-size) - 2px) var(--bg-size)) var(--grid-offset) var(--grid-offset) / var(--bg-size) 100%, transparent;
/*	background: var(--bg);*/
	position: fixed;
	inset: 0;
	height: 100vh;
	width: 100vw;
	-webkit-mask: radial-gradient(circle at 0% 0%, hsl(0 0% 100% / 0.5), transparent);
}

.form-group:focus-within label {
	color: var(--color);
}
.form-group:focus-within input {
	border-color: var(--color);
	color: var(--color);
}
.form-group:focus-within button {
	color: var(--color);
}

input {
	font-family: "Geist Mono", monospace;
	font-size: 1.75rem;
	padding: 1rem 2rem;
  padding-right: 4rem;
	letter-spacing: 0.2ch;
	border-radius: 6px;
	color: var(--color-alpha);
	border-color: var(--color-alpha);
	border-style: solid;
	background: var(--input-bg);
	outline: none;
	transition: border-color 0.2s, color 0.2s
}

label {
	position: absolute;
	color: var(--color-alpha);
	bottom: calc(100% + 0.5rem);
	letter-spacing: 0.2ch;
	transition: color 0.2s;
}

.form-group {
	position: relative;
}

.eye circle:nth-of-type(2) {
	fill: var(--glint);
}

button {
	padding: 0;
	display: grid;
	place-items: center;
	height: 100%;
	aspect-ratio: 1;
	border-radius: 12px;
	border: 0;
	background: linear-gradient(hsl(0 0% var(--button-shade) / calc(var(--active, 0) * 0.5)), hsl(0 0% var(--button-shade) / calc(var(--active, 0) * 0.5))) padding-box;
	border: 6px solid transparent;
	transition: background 0.125s;
	color: var(--color-alpha);
	position: absolute;
	right: 0;
	z-index: 2;
	top: 50%;
	cursor: pointer;
	translate: 0 -50%;
	outline: 0;
}

input::selection {
	background: var(--selection);
}

button:is(:focus-visible, :hover) {
	--active: 1;
}

button svg {
	width: 75%;
}

.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border-width: 0;
}
import { gsap } from 'https://cdn.skypack.dev/gsap@3.11.0';

gsap.registerPlugin(ScrambleTextPlugin, MorphSVGPlugin);

const BLINK_SPEED = 0.075;
const TOGGLE_SPEED = 0.125;
const ENCRYPT_SPEED = 1;

let busy = false;

const EYE = document.querySelector('.eye');
const TOGGLE = document.querySelector('button');
const INPUT = document.querySelector('#password');
const PROXY = document.createElement('div');

// 'upperAndLowerCase'
const chars =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~,.<>?/;":][}{+_)(*&^%$#@!±=-§';

let blinkTl;
const BLINK = () => {
  const delay = gsap.utils.random(2, 8);
  const duration = BLINK_SPEED;
  const repeat = Math.random() > 0.5 ? 3 : 1;
  blinkTl = gsap.timeline({
    delay,
    onComplete: () => BLINK(),
    repeat,
    yoyo: true }).

  to('.lid--upper', {
    morphSVG: '.lid--lower',
    duration }).

  to('#eye-open path', {
    morphSVG: '#eye-closed path',
    duration },
  0);
};

BLINK();

const posMapper = gsap.utils.mapRange(-100, 100, 30, -30);
let reset;
const MOVE_EYE = ({ x, y }) => {
  if (reset) reset.kill();
  reset = gsap.delayedCall(2, () => {
    gsap.to('.eye', { xPercent: 0, yPercent: 0, duration: 0.2 });
  });
  const BOUNDS = EYE.getBoundingClientRect();
  // Get distance and angle between two points
  gsap.set('.eye', {
    xPercent: gsap.utils.clamp(-30, 30, posMapper(BOUNDS.x - x)),
    yPercent: gsap.utils.clamp(-30, 30, posMapper(BOUNDS.y - y)) });

};

window.addEventListener('pointermove', MOVE_EYE);

// Trick is to animate from discs and to discs.

TOGGLE.addEventListener('click', () => {
  if (busy) return;
  const isText = INPUT.matches('[type=password]');
  const val = INPUT.value;
  busy = true;
  // Need to stop the blink here and kill it off. 
  TOGGLE.setAttribute('aria-pressed', isText);
  const duration = TOGGLE_SPEED;

  if (isText) {
    if (blinkTl) blinkTl.kill();

    gsap.timeline({
      onComplete: () => {
        busy = false;
      } })

    // Close the eye first and kill the TL
    .to('.lid--upper', {
      morphSVG: '.lid--lower',
      duration }).

    to('#eye-open path', {
      morphSVG: '#eye-closed path',
      duration },
    0)
    // Decrypt the text input
    .to(PROXY, {
      duration: ENCRYPT_SPEED,
      onStart: () => {
        INPUT.type = 'text';
      },
      onComplete: () => {
        PROXY.innerHTML = '';
        INPUT.value = val;
      },
      scrambleText: {
        chars,
        text:
        INPUT.value.charAt(INPUT.value.length - 1) === ' ' ?
        `${INPUT.value.slice(0, INPUT.value.length - 1)}${chars.charAt(
        Math.floor(Math.random() * chars.length))
        }` :
        INPUT.value },

      onUpdate: () => {
        const len = val.length - PROXY.innerText.length;
        INPUT.value = `${PROXY.innerText}${new Array(len).fill('•').join('')}`;
      } },
    0);
  } else {
    gsap.timeline({
      onComplete: () => {
        BLINK();
        busy = false;
      } }).

    to('.lid--upper', {
      morphSVG: '.lid--upper',
      duration }).

    to('#eye-open path', {
      morphSVG: '#eye-open path',
      duration },
    0).
    to(PROXY, {
      duration: ENCRYPT_SPEED,
      onComplete: () => {
        INPUT.type = 'password';
        INPUT.value = val;
        PROXY.innerHTML = '';
      },
      scrambleText: {
        chars,
        text: new Array(INPUT.value.length).fill('•').join('') },

      onUpdate: () => {
        INPUT.value = `${PROXY.innerText}${val.slice(
        PROXY.innerText.length,
        val.length)
        }`;
      } },
    0);
  }
});


const FORM = document.querySelector('form');
FORM.addEventListener('submit', event => event.preventDefault());