自分用のメモになります。最後に、写真ギャラリーを完成させたいと思います。
前回は以下を参照して下さい。
目次
やりたいこと
表示するサムネイルにスタイルを当てたいと思います。
隣り合うサムネイルの間にボーダーを入れ、各サムネイルに間隔が空くように表示させます。
実装
Appコンポーネント
import './App.css';
import './dennie.css';
import React from 'react';
import PhotoGallery from './PhotoGallery';
import ImgPathList from './ImgPathList';
function App() {
// 列の数(1列に表示する写真の数)
const columnCount = 4;
// テーブルの幅(0〜1で設定する。ex)0.8 は幅80%)
const tableWidth = 0.8;
// クラス名(オプション)
// const className = "dennie_container";
// 第一引数がサムネイルパス一覧。第二引数はサムネイルパス一覧を更新する関数。
const [imagePathList, next] = ImgPathList(columnCount);
// サムネイルの左間隔を決める。
const thumbnailLeftBorder = "5";
// サムネイルのトップ間隔を決める。
const thumbnailTopBorder = "3";
// 写真(サムネイル)の表示
const RenderItem = ({columnIndex, rowIndex, style, data}) => {
// トップボーダーを設定する。
let colBorder = {
"border-top": thumbnailTopBorder + "px solid #ffffff"
};
// 先頭行のトップボーダーは削除する。
if(rowIndex === 0){
delete colBorder["border-top"];
}
// 先頭列以外の場合、左ボーダーを設定する。
const colNumber = columnIndex % columnCount;
if(colNumber !== 0){
colBorder["border-left"] = thumbnailLeftBorder + "px solid #ffffff";
}
return (
<div style={{...style}}>
<img src={data[rowIndex][columnIndex]} width={"100%"} style={colBorder}/>
</div>
);
}
return (
<>
<PhotoGallery
imgPathList = {imagePathList}
renderItem = {RenderItem}
columnCount = {columnCount}
tableWidth = {tableWidth}
upDateList = {next}
thumbnailLeftBorder = {Number(thumbnailLeftBorder)}
// className = {className}
/>
</>
);
}
export default App;
dennie.css (任意なくてもOK)
前回と同じです。
.dennie_container {
border: 4px solid red;
}
PhotoGalleryコンポーネント
import './PhotoGallery.css';
import React, { useLayoutEffect , useState} from 'react';
import {FixedSizeGrid} from 'react-window';
function PhotoGallery({
imgPathList = [], // サムネイルパス一覧
renderItem, // カラム表示
columnCount, // カラム数
tableWidth = 1, // テーブルの幅(1で横幅マックス)(オプション)
orgItemSizeWith = 1, // サムネイルの横の長さ(オプション)
orgItemSizeHigt = 1, // サムネイルの縦の長さ(オプション)
upDateList = f => f, // サムネイルパス一覧更新関数(オプション)
thumbnailLeftBorder = 0, // サムネイルの間隔。テーブルの長さに足す必要がある。
className = 'container_center', // クラス名(オプション)
}) {
// テーブルの高さ、幅を保持する。
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
// テーブルの高さ、幅をリサイズする。
const resize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
}
useLayoutEffect(() => {
window.addEventListener("resize", resize);
resize();
},[])
// 列の幅
let colWidth = (width * tableWidth) / columnCount;
// 列の高さ(行の高さ) 列の幅 * 縦横比率
let colHeight = colWidth * (orgItemSizeHigt / orgItemSizeWith);
// データリストの高さ
let listHeight = colHeight * imgPathList.length;
// スクロールイベント。スクロール位置とデータリストの高さを判定して、ボトムになりそうな場合、サムネイルパス一覧を更新する。
const onScroll = ({
scrollTop,
}) => {
if(scrollTop > listHeight - 1000){
upDateList();
}
}
return (
<FixedSizeGrid
className = {className}
columnCount = {columnCount}
columnWidth = {colWidth}
height = {height}
width = {width * tableWidth + thumbnailLeftBorder}
rowCount = {imgPathList.length}
rowHeight = {colHeight}
itemData = {imgPathList}
onScroll = {onScroll}
>
{renderItem}
</FixedSizeGrid>
);
}
export default PhotoGallery;
PhotoGallery.css
前回と同じです。
.container_center {
margin: 0 auto;
}
ImgPathList フック
前回と同じです。
import {useState} from 'react';
function ImgPathList(columnCount = 5, parListCount = 10) {
// 現在のパス名のカウント
const [currentNumber, setCurrentNumber] = useState(1014659);
// サムネイルパス一覧
const [imagePathList, setImagePathList] = useState([]);
const next = () => {
// 新たにサムネイルパス一覧を生成する。
let cnt = 0;
let imgPathList = [...Array(parListCount)].map(element => {
return [...Array(columnCount)].map(elem => {
const strCurrentNumber = String(currentNumber + cnt);
const imagePath = `https://dennie.tokyo/norway/img/photos/square/P${strCurrentNumber}.jpg`;
cnt++;
return imagePath;
});
});
// 現在のパス名のカウントを増えた分更新する。
setCurrentNumber(currentNumber + cnt - 1);
// サムネイルパス一覧を更新する。
setImagePathList(imagePathList.concat(imgPathList));
}
return [imagePathList, next];
}
export default ImgPathList;
最後に
特にありません。