「画像にマウスオーバーするとポップアップが出る」ということを実現する方法は何通りかあると思います。
この記事ではReactのcreatePortalを使用して、画像にポップアップを出す方法をご紹介。
プログラムの概要
表示された画像にマウスオーバーするととセリフのようなポップアップが出て、マウスのポインターが外れると、ポップアップが消える、といっただけのプログラムです。
Popup.js
// Popup.js
import { useState } from "react";
import { createPortal } from "react-dom";
import { Image, Text } from "@chakra-ui/react";
import { Link } from "react-router-dom";
import DOG_IMG_AKITA from "../image/akita.jpg";
import DOG_IMG_NAYAMU from "../image/nayamu.jpg";
import DOG_IMG_TANOSHI from "../image/tanoshi.jpg";
const Popup = () => {
const [popup, setPopup] = useState(false);
const [insTag, setInsTag] = useState("");
const [insMSG, setInsMSG] = useState("");
const PopupPortal = ({ children }) => {
const target = document.querySelector(insTag);
return createPortal(children, target);
};
const popupMSG = (cls,message) => {
setInsTag(cls);
setInsMSG(message);
setPopup(true);
}
return (
<div>
<div className="imgContainer">
<Image
boxSize="100px"
objectFit="cover"
src={DOG_IMG_AKITA}
m={2}
alt="犬 飽きた"
onMouseOver={() => popupMSG('.akita','飽きたなぁ~')}
onMouseLeave={() => setPopup(false)}
/>
<div className="akita"></div>
</div>
<div className="imgContainer">
<Image
boxSize="100px"
objectFit="cover"
src={DOG_IMG_NAYAMU}
m={2}
alt="犬 悩む"
onMouseOver={() => popupMSG('.nayamu','むずかしいなぁ~')}
onMouseLeave={() => setPopup(false)}
/>
<div className="nayamu"></div>
</div>
<div className="imgContainer">
<Image
boxSize="100px"
objectFit="cover"
src={DOG_IMG_TANOSHI}
m={2}
alt="「たのしいなぁ~」"
onMouseOver={() => popupMSG('.tanoshi','たのしいなぁ~')}
onMouseLeave={() => setPopup(false)}
/>
<div className="tanoshi"></div>
</div>
{popup && (
<PopupPortal>
<div className="msg">
<Text>{insMSG}</Text>
</div>
</PopupPortal>
)}
<div className="link-css">
<Link to={`/`}>homeへ</Link>
</div>
</div>
);
};
export default Popup;
ポップアップを実現しているコードが上記のPopup.jsです。
このコンポーネントをApp.jsでimportして実現しています。
では、以下にプログラムの詳細を説明していきます。
useState
import { useState } from "react";
・・・
const [popup, setPopup] = useState(false); // 状態管理用false:ポップを出さない。true:ポップを出す。
const [insTag, setInsTag] = useState(""); // ポップをどこに出すかを保存しておく
const [insMSG, setInsMSG] = useState(""); // ポップのメッセージを保存しておく
ポップアップを出すか/出さないかの判定。
ポップアップをどこに出すのか。
ポップアップの内容の格納。
にuseStateを使いました。
createPortal
ページの何処にどのようなポータル出すかを制御します。
import { createPortal } from "react-dom";
・・・
const PopupPortal = ({ children }) => {
const target = document.querySelector(insTag);
return createPortal(children, target);
};
「insTag」で示された場所に、「children」の内容を表示する、といった意味。
{popup && ( {// popupがtrueなら<PopupPotal>以下を表示する。}
<PopupPortal>
<div className="msg">
<Text>{insMSG}</Text>
</div>
</PopupPortal>
)}
popupがtrueなら<PopupPortal>以下を表示する処理。
{insMSG}には、マウスオーバーした画像のメッセージが格納されている。
マウスオーバー、マウスリーフイベント
const popupMSG = (cls,message) => {
setInsTag(cls);
setInsMSG(message);
setPopup(true);
}
・・・
<div className="imgContainer">
<Image
boxSize="100px"
objectFit="cover"
src={DOG_IMG_TANOSHI}
m={2}
alt="「たのしいなぁ~」"
onMouseOver={() => popupMSG('.tanoshi','たのしいなぁ~')}
onMouseLeave={() => setPopup(false)}
/>
<div className="tanoshi"></div>
</div>
onMouseOverイベントが発生すると、
を引数として、popupMSGがコールされる。
popupMSG()では、
をしています。
onMouseLeaveでは、ポップアップを消すためにpopupをfalseにしています。
css
どんな感じのポップアップにするかは、<PopupPortal>で出力するコンポーネントのcssに依存します。
参考に、cssのコードは示しますが、ここはcssの知識を駆使して、お好みのデザインをしてください。
.imgContainer {
position: relative;
}
.msg {
position: absolute;
top:10%;
left: 55%;
z-index: 100;
border: solid 1px ;
border-radius: 8px;
background-color: rgba(255, 255, 255, 0.3);
}
言い訳ですが、目的がcreatePortalでのポップアップ表示の実現なので、デザインはおざなりです。
最後に
一からポップアップのプログラムを作りたい方がいる場合も考えて、参考のためにディレクトリ構造やApp.jsのコードを紹介しておきます。
ディレクトリ構造
当該プログラムのsrcディレクトリ配下の構造です。
createPortalを使ったサンプルプログラムです。ポップアップの他にも、モーダルとトーストのサンプルも含まれています。
App.js
import React from "react";
import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./components/Home";
import Modal from "./components/Modal";
import Popup from "./components/Popup";
import Toast from "./components/Toast";
function App() {
return (
<div className="App">
<BrowserRouter>
<Routes>
<Route path={"/"} element={<Home />} />
<Route path={"/modal"} element={<Modal />} />
<Route path={"/popup"} element={<Popup />} />
<Route path={"/toast"} element={<Toast />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
最後に
このブログに掲載されているコードは、著作権者(私)に帰属します。コードを自由に使用、複製、改変、配布、販売、サブライセンスできます。また、コードを使用した結果、何らかの損害が発生した場合でも、著作権者は一切責任を負いません。