Introduce
- Layout masonry is a column-based grid layout, unlike a grid, it has no fixed height. Overall, masonry layout will optimize the space used in a web page by minimizing all the gaps between elements. The simplest and most intuitive example is https://www.pinterest.com/ the space between the images is just the section between the images, no extra space
- What virtualized is, in my series of articles, there are quite a few related articles, you can check again.
- A long time ago, after entering the pinterest page, I wanted to be able to create such a layout, if you pay attention, then pinterest just uses this masonry layout, both using virtualized method, and using method load more, as well as algorithms to optimize images to speed up loading. But today I only focus on the first two, layout masonry and combine it with virtualized. So today I will use 1 library called masonic to support this work better.
For example
For quick, this time we use create-react-app to operate offline: create-react-app masonry_layout I install the masonic library too: npm i masonic
In the App.js file, I create a list of images with 5000 images:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">const</span> items <span class="token operator">=</span> Array <span class="token punctuation">.</span> <span class="token function">from</span> <span class="token punctuation">(</span> <span class="token function">Array</span> <span class="token punctuation">(</span> <span class="token number">5000</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> randomPhoto <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">random</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">5000</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span> <span class="token keyword">const</span> randomHeight <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">random</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">5</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">2</span> <span class="token keyword">const</span> randomWidth <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">random</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">5</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">2</span> <span class="token keyword">const</span> imgUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">https://picsum.photos/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> randomWidth <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">00/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> randomHeight <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">00?random=</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> randomPhoto <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token keyword">return</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> i <span class="token operator">++</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Img-title-</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> i <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">,</span> src <span class="token operator">:</span> imgUrl <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
Next is the Masonry component:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token operator"><</span> Masonry items <span class="token operator">=</span> <span class="token punctuation">{</span> items <span class="token punctuation">}</span> <span class="token comment">// Adds 8px of space between the grid cells</span> columnGutter <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">8</span> <span class="token punctuation">}</span> <span class="token comment">// Sets the minimum column width to 172px</span> columnWidth <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">300</span> <span class="token punctuation">}</span> <span class="token comment">// Pre-renders 5 windows worth of content</span> overscanBy <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">5</span> <span class="token punctuation">}</span> <span class="token comment">// This is the grid item component</span> render <span class="token operator">=</span> <span class="token punctuation">{</span> ImageCard <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> |
Here is the complete App.js file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> Masonry <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"masonic"</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> ImageCard <span class="token keyword">from</span> <span class="token string">'./ImageCard'</span> <span class="token keyword">import</span> <span class="token string">'./App.css'</span> <span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span> <span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> items <span class="token operator">=</span> Array <span class="token punctuation">.</span> <span class="token function">from</span> <span class="token punctuation">(</span> <span class="token function">Array</span> <span class="token punctuation">(</span> <span class="token number">5000</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> randomPhoto <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">random</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">5000</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span> <span class="token keyword">const</span> randomHeight <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">random</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">5</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">2</span> <span class="token keyword">const</span> randomWidth <span class="token operator">=</span> Math <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">random</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">5</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">2</span> <span class="token keyword">const</span> imgUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">https://picsum.photos/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> randomWidth <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">00/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> randomHeight <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">00?random=</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> randomPhoto <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token keyword">return</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> i <span class="token operator">++</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Img-title-</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> i <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">,</span> src <span class="token operator">:</span> imgUrl <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> main className <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">'container'</span> <span class="token punctuation">}</span> <span class="token operator">></span> <span class="token operator"><</span> div className <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">'masonic'</span> <span class="token punctuation">}</span> <span class="token operator">></span> <span class="token operator"><</span> Masonry items <span class="token operator">=</span> <span class="token punctuation">{</span> items <span class="token punctuation">}</span> columnGutter <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">8</span> <span class="token punctuation">}</span> <span class="token comment">// Set khoảng cách giữa các column</span> columnWidth <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">300</span> <span class="token punctuation">}</span> <span class="token comment">// Set chiều rộng tối thiểu là 300px</span> overscanBy <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token number">5</span> <span class="token punctuation">}</span> <span class="token comment">// Giá trị để render trước khi scroll tới</span> render <span class="token operator">=</span> <span class="token punctuation">{</span> ImageCard <span class="token punctuation">}</span> <span class="token comment">// Grid item của component</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> main <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App <span class="token punctuation">;</span> |
Next is the ImageCard components used to render each cell of the layout masonry: the ImageCard.js file
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">const</span> <span class="token function-variable function">ImageCard</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> data <span class="token operator">:</span> <span class="token punctuation">{</span> id <span class="token punctuation">,</span> name <span class="token punctuation">,</span> src <span class="token punctuation">}</span> <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> div className <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">'card'</span> <span class="token punctuation">}</span> <span class="token operator">></span> <span class="token operator"><</span> img className <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">'img'</span> <span class="token punctuation">}</span> alt <span class="token operator">=</span> <span class="token string">"kitty"</span> src <span class="token operator">=</span> <span class="token punctuation">{</span> src <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> span children <span class="token operator">=</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> ImageCard |
Finally, I have added some css to make the layout easier to see in the App.css file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token selector">.masonic</span> <span class="token punctuation">{</span> <span class="token property">padding</span> <span class="token punctuation">:</span> 8px <span class="token punctuation">;</span> <span class="token property">width</span> <span class="token punctuation">:</span> 100% <span class="token punctuation">;</span> <span class="token property">max-width</span> <span class="token punctuation">:</span> 960px <span class="token punctuation">;</span> <span class="token property">margin</span> <span class="token punctuation">:</span> 163px auto 0 <span class="token punctuation">;</span> <span class="token property">box-sizing</span> <span class="token punctuation">:</span> border-box <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.container</span> <span class="token punctuation">{</span> <span class="token property">min-height</span> <span class="token punctuation">:</span> 100vh <span class="token punctuation">;</span> <span class="token property">width</span> <span class="token punctuation">:</span> 100% <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.card</span> <span class="token punctuation">{</span> <span class="token property">display</span> <span class="token punctuation">:</span> flex <span class="token punctuation">;</span> <span class="token property">flex-direction</span> <span class="token punctuation">:</span> column <span class="token punctuation">;</span> <span class="token property">border-radius</span> <span class="token punctuation">:</span> 6px <span class="token punctuation">;</span> <span class="token property">justify-content</span> <span class="token punctuation">:</span> center <span class="token punctuation">;</span> <span class="token property">align-items</span> <span class="token punctuation">:</span> center <span class="token punctuation">;</span> <span class="token property">transition</span> <span class="token punctuation">:</span> transform 100ms ease-in-out <span class="token punctuation">;</span> <span class="token property">width</span> <span class="token punctuation">:</span> 100% <span class="token punctuation">;</span> <span class="token property">min-height</span> <span class="token punctuation">:</span> 100px <span class="token punctuation">;</span> <span class="token property">overflow</span> <span class="token punctuation">:</span> hidden <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.img</span> <span class="token punctuation">{</span> <span class="token property">width</span> <span class="token punctuation">:</span> 100% <span class="token punctuation">;</span> <span class="token property">display</span> <span class="token punctuation">:</span> block <span class="token punctuation">;</span> <span class="token property">border-top-left-radius</span> <span class="token punctuation">:</span> 6px <span class="token punctuation">;</span> <span class="token property">border-top-right-radius</span> <span class="token punctuation">:</span> 6px <span class="token punctuation">;</span> <span class="token property">display</span> <span class="token punctuation">:</span> block <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
And this is the result:
If you inspect the element, you already have the layout masonry along with the virtualized method
Conclude
So I have created for me 1 UI layout like pinterest already, please try it, wish you success (yaoming)