UIのドロップダウンメニュー


先日、私は次の使用中の反応で仕事の新しい内部アプリをプロトタイピングされました.jsすぐに地面からそれを得るために、私はTruwind CSSを使いました.私のアプリでは、シンプルなドロップダウンメニューを作成する必要があり、私はTailwind UIの例を見てどのようにそれをやった.
実際には、ドロップダウンメニューを作成するのと同じくらい簡単ではありません.まず、マウスクリックを処理しなければなりません.第二に、Escapeキーを押して、現在開いている場合はメニューを閉じる必要があります.第三に、より多くの生きている感じのように、メニューに素敵なアニメーションを追加する必要があります.

私が望んだように、反応でメニューを実行することは全くまっすぐでありませんでした.テールウインドスタイル自体は問題ではありませんが、「クリックアウェイ」または「外側をクリック」機能を処理し、エスケープキーを処理する方法を理解するのに少し時間がかかりました.その上で、私はCSS遷移をどう反応させるかを研究しなければなりませんでした.Trewindのクリエイターは、機能が組み込まれていない反応として役立つtransition libraryを作成したことが判明.
「反応クリック・クリック・リスナー」のためにGoogle searchをすることは、本当に助けませんでした.“反応をクリックして外側”と“反応クリックを離れて”NPMの検索は、私は必要以上に多くの結果を返しました.確かに、反応ライブラリがたくさんありますが、もっと簡単に処理する方法があるべきだと感じました.
次はこちら.JS(反応+ typescript)コード私は終わりました.
import Link from 'next/link';
import React, { useState, useRef, useEffect } from 'react';
import { Transition } from '@tailwindui/react';

const Menu = ({ user }) => {
  const [show, setShow] = useState(false);
  const container = useRef(null);

  useEffect(() => {
    const handleOutsideClick = (event: MouseEvent) => {
      if (!container.current.contains(event.target)) {
        if (!show) return;
        setShow(false);
      }
    };

    window.addEventListener('click', handleOutsideClick);
    return () => window.removeEventListener('click', handleOutsideClick);
  }, [show, container]);

  useEffect(() => {
    const handleEscape = (event: KeyboardEvent) => {
      if (!show) return;

      if (event.key === 'Escape') {
        setShow(false);
      }
    };

    document.addEventListener('keyup', handleEscape);
    return () => document.removeEventListener('keyup', handleEscape);
  }, [show]);

  return (
    <div ref={container} className="relative">
      <button
        className="menu focus:outline-none focus:shadow-solid "
        onClick={() => setShow(!show)}
      >
        <img
          className="w-10 h-10 rounded-full"
          src={user.picture}
          alt={user.name}
        />
      </button>

      <Transition
        show={show}
        enter="transition ease-out duration-100 transform"
        enterFrom="opacity-0 scale-95"
        enterTo="opacity-100 scale-100"
        leave="transition ease-in duration-75 transform"
        leaveFrom="opacity-100 scale-100"
        leaveTo="opacity-0 scale-95"
      >
        <div className="origin-top-right absolute right-0 w-48 py-2 mt-1 bg-gray-800 rounded shadow-md">
          <Link href="/profile">
            <a className="block px-4 py-2 hover:bg-green-500 hover:text-green-100">
              Profile
            </a>
          </Link>
          <Link href="/api/logout">
            <a className="block px-4 py-2 hover:bg-green-500 hover:text-green-100">
              Logout
            </a>
          </Link>
        </div>
      </Transition>
    </div>
  );
};

export default Menu;
私が反応インプリメンテーションでされたとき、私はSvelteで同じメニューをどのように実装するかについて、私自身に思いました.それで私はいくつかの時間をSvelteにそれをポートに取った.
Svelteについての多くのニッチの一つは、CSSの遷移とアニメーションが組み込まれていることです.これが私のテイクです.
<script>
  import { onMount } from 'svelte';
  import { scale } from 'svelte/transition';

  export let user;

  let show = false; // menu state
  let menu = null; // menu wrapper DOM reference

  onMount(() => {
    const handleOutsideClick = (event) => {
      if (show && !menu.contains(event.target)) {
        show = false;
      }
    };

    const handleEscape = (event) => {
      if (show && event.key === 'Escape') {
        show = false;
      }
    };

    // add events when element is added to the DOM
    document.addEventListener('click', handleOutsideClick, false);
    document.addEventListener('keyup', handleEscape, false);

    // remove events when element is removed from the DOM
    return () => {
      document.removeEventListener('click', handleOutsideClick, false);
      document.removeEventListener('keyup', handleEscape, false);
    };
  });
</script>

<div class="relative" bind:this={menu}>
  <div>
    <button
      on:click={() => (show = !show)}
      class="menu focus:outline-none focus:shadow-solid"
    >
      <img class="w-10 h-10 rounded-full" src={user.picture} alt={user.name} />
    </button>

    {#if show}
      <div
        in:scale={{ duration: 100, start: 0.95 }}
        out:scale={{ duration: 75, start: 0.95 }}
        class="origin-top-right absolute right-0 w-48 py-2 mt-1 bg-gray-800
          rounded shadow-md"
      >
        <a
          href="/profile"
          class="block px-4 py-2 hover:bg-green-500 hover:text-green-100"
        >Profile</a>
        <a
          href="/api/logout"
          class="block px-4 py-2 hover:bg-green-500 hover:text-green-100"
        >Logout</a>
      </div>
    {/if}
  </div>
</div>
確かに、コードの量はほとんど反応のSvelteでは少ないが、認識の負荷についてはどうですか?どれを読んで理解しやすいですか?あなたは判事です.