{"id":550,"date":"2023-08-12T07:17:00","date_gmt":"2023-08-12T04:17:00","guid":{"rendered":"https:\/\/shedov.top\/ru\/?p=550"},"modified":"2026-01-12T00:22:18","modified_gmt":"2026-01-11T21:22:18","slug":"animirovannoe-dropdown-menyu-v-react-s-ispolzovaniem-sobytiya-onanimationend","status":"publish","type":"post","link":"https:\/\/shedov.top\/ru\/animirovannoe-dropdown-menyu-v-react-s-ispolzovaniem-sobytiya-onanimationend\/","title":{"rendered":"\u0410\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 dropdown \u043c\u0435\u043d\u044e \u0432 React \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u2014 onAnimationEnd"},"content":{"rendered":"\n\n<div class=\"blog_post_image_wrap\">\n<div class=\"blog_post_image blog_post_image_cover\">\n   <a href=\"https:\/\/animated-dropdown-menu-in-react.vercel.app\/\" target=\"_blank\" rel=\"noopener\">\n    <img decoding=\"async\" src=\"https:\/\/shedov.top\/wp-content\/images\/animated_dropdown_menu_in_react.webp\" alt=\"animated dropdown menu in react\"> \n     <\/a>\n<\/div>\n<\/div>\n\n\n\n\n<p style=\"margin-top: 30px;\">\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435, \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f onAnimationEnd. onAnimationEnd \u2013  \u044d\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u2013  animationEnd, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f CSS-\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430. \u0412 \u044d\u0442\u043e\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0438 \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044e \u0437\u0430\u043a\u0440\u044b\u0442\u043e, \u043e\u043d\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 DOM.<\/p>\n\n\n\n&nbsp;\n\n\n\n<h2 class=\"wp-block-heading has-text-align-center\">App.jsx<\/h2>\n\n\n\n<pre class=\"wp-block-code lang-jsx line-numbers\"><code>import { Menu } from \".\/components\";\n\nfunction App() {\n\n  return (\n    &lt;div className=\"App\">\n      &lt;Menu \/>\n    &lt;\/div>\n  );\n}\nexport default App;<\/code><\/pre>\n\n\n\n&nbsp;\n\n\n\n<h2 class=\"wp-block-heading has-text-align-center\">Menu.jsx<\/h2>\n\n\n\n<pre class=\"wp-block-code lang-jsx line-numbers\"><code>import {\n  useState,\n  useEffect,\n  useRef\n} from \"react\";\n\nimport { Kitten } from \"..\/..\/components\";\nimport styles from \".\/Menu.module.css\";\n\nexport function Menu() {\n  const &#91;showMenu, setShowMenu] = useState(false);\n  const &#91;fadeOut, setFadeOut] = useState(false);\n  const buttonShowMenu = (visibility) => {\n    if (visibility) {\n      setShowMenu(true);\n    } else {\n      setFadeOut(true);\n    }\n  };\n\n  \/\/ Click tracking outside the menu\n  const menuRef = useRef();\n  useEffect(() => {\n    if (menuRef.current) {\n      const handler = (e) => {\n        if (!menuRef.current.contains(e.target)) {\n          setFadeOut(true);\n        }\n      };\n      document.addEventListener(\"mousedown\", handler);\n      return () => {\n        document.removeEventListener(\"mousedown\", handler);\n      };\n    }\n  });\n\n  return (\n    &lt;div className={styles.menu_wrap}>\n      &lt;button\n        onClick={() => buttonShowMenu(!showMenu)}\n      >\n        &lt;Kitten \/>\n      &lt;\/button>\n      {showMenu &amp;&amp; (\n        &lt;div\n          ref={menuRef}\n          className={\n            fadeOut\n              ? `${styles.menu} ${styles.menu__fade_out}`\n              : `${styles.menu}`\n          }\n          onAnimationEnd={(e) => {\n            if (e.animationName === styles.fadeOut) {\n              setShowMenu(false);\n              setFadeOut(false);\n            }\n          }}\n        >\n          &lt;ul className={styles.menu_list}>\n            &lt;li>My profile&lt;\/li>\n            &lt;li>Settings&lt;\/li>\n            &lt;li>Exit&lt;\/li>\n          &lt;\/ul>\n        &lt;\/div>\n      )}\n    &lt;\/div>\n  );\n}\n<\/code><\/pre>\n\n\n\n&nbsp;\n\n\n\n<h2 class=\"wp-block-heading has-text-align-center\">Menu.module.css<\/h2>\n\n\n\n<pre class=\"wp-block-code lang-css line-numbers\"><code>.menu_wrap {\n  width: 100%;\n  max-width: 200px;\n  margin-right: 15px;\n  margin-left: 15px;\n}\n\nbutton {\n  margin-left: auto;\n  margin-right: auto;\n  margin-top: 7px;\n  margin-bottom: 7px;\n  width: 50px;\n  height: 50px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  color: #222;\n  box-shadow: rgb(0 0 0 \/ 18%) 0.2px 0.2px 2.5px;\n  border-radius: 50%;\n  background-color: rgb(255, 255, 255);\n  transition: all 250ms ease;\n  cursor: pointer;\n  border: none;\n}\n\n@media (min-width: 1000px) {\n  button:hover {\n    transition: all 250ms ease;\n    box-shadow: rgb(0 0 0 \/ 18%) 0.3px 0.3px 4px;\n  }\n}\n\n.menu {\n  width: 100%;\n  max-width: 100px;\n  left: 0;\n  right: 0;\n  margin: auto;\n  border-bottom-right-radius: 5px;\n  border-bottom-left-radius: 5px;\n  border-top-left-radius: 0px;\n  border-top-right-radius: 0px;\n  position: absolute;\n  animation: fadeIn 0.3s forwards;\n  opacity: 0;\n  background-color: rgb(255, 255, 255);\n  box-shadow: 0 4px 16px rgb(132 134 136 \/ 9%), 0 2px 2px rgb(138 140 143 \/ 10%);\n}\n\n.menu_list li {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-family: Arial, Helvetica, sans-serif;\n  font-size: 17px;\n  color: #222;\n  cursor: pointer;\n  transition: all 300ms ease;\n  height: 25px;\n  margin-top: 12px;\n  margin-bottom: 12px;\n}\n\n@media (min-width: 1000px) {\n  .menu_list li:hover {\n    transition: all 300ms ease;\n    color: #545454;\n  }\n}\n\n.menu__fade_out {\n  animation: fadeOut 0.3s forwards;\n  opacity: 1;\n}\n\n@keyframes fadeIn {\n  from {\n    opacity: 0;\n  }\n\n  to {\n    opacity: 1;\n  }\n}\n\n@keyframes fadeOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n  }\n}<\/code><\/pre>\n\n\n\n<div class=\"blog_post_links_with_code\">\n<p><a style=\"color: var(--live_text_color);\" href=\"https:\/\/animated-dropdown-menu-in-react.vercel.app\/\" target=\"_blank\" rel=\"noopener\">LIVE<\/a>&nbsp;&nbsp;&nbsp;<a href=\"https:\/\/github.com\/AndrewShedov\/animated-dropdown-menu-in-react\" target=\"_blank\" rel=\"noopener\">GitHub<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435, \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f onAnimationEnd. onAnimationEnd \u2013 \u044d\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u2013 animationEnd, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f CSS-\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430. \u0412 \u044d\u0442\u043e\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0438 \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044e \u0437\u0430\u043a\u0440\u044b\u0442\u043e, \u043e\u043d\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 DOM. &nbsp; App.jsx &nbsp; Menu.jsx &nbsp; Menu.module.css LIVE&nbsp;&nbsp;&nbsp;GitHub","protected":false},"author":1,"featured_media":2692,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,19,4,18,16,10,17],"tags":[],"class_list":["post-550","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-css","category-dropdown","category-js","category-onanimationend","category-react","category-animation","category-animation-react"],"_links":{"self":[{"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/posts\/550","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/comments?post=550"}],"version-history":[{"count":59,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/posts\/550\/revisions"}],"predecessor-version":[{"id":4370,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/posts\/550\/revisions\/4370"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/media\/2692"}],"wp:attachment":[{"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/media?parent=550"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/categories?post=550"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shedov.top\/ru\/wp-json\/wp\/v2\/tags?post=550"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}